From 11154ad9ac41999857377a99102c0cc3ece4f9e8 Mon Sep 17 00:00:00 2001 From: Shemy Gan Date: Fri, 20 Dec 2024 10:59:12 -0500 Subject: [PATCH] - Code clean up --- .../src/Pages/Status/CreateStatus/index.jsx | 108 ++++++++++-------- Client/src/Pages/Status/index.jsx | 8 +- Client/src/Routes/index.jsx | 6 + Client/src/Validation/validation.js | 12 +- 4 files changed, 83 insertions(+), 51 deletions(-) diff --git a/Client/src/Pages/Status/CreateStatus/index.jsx b/Client/src/Pages/Status/CreateStatus/index.jsx index 297603015..8be2e4a33 100644 --- a/Client/src/Pages/Status/CreateStatus/index.jsx +++ b/Client/src/Pages/Status/CreateStatus/index.jsx @@ -4,50 +4,70 @@ import { Box, Tab, useTheme, Stack, Button } from "@mui/material"; import TabContext from "@mui/lab/TabContext"; import TabList from "@mui/lab/TabList"; import GeneralSettingsPanel from "../../../Components/TabPanels/Status/GeneralSettingsPanel"; -import { capitalizeFirstLetter } from "../../../Utils/stringUtils"; import ContentPanel from "../../../Components/TabPanels/Status/ContentPanel"; import { publicPageGeneralSettingsValidation } from "../../../Validation/validation"; import { hasValidationErrors } from "../../../Validation/error"; import { StatusFormProvider } from "../CreateStatusContext"; +import { formatBytes } from "../../../Utils/fileUtils"; +import { useSelector } from "react-redux"; +import { createToast } from "../../../Utils/toastUtils"; +import { networkService } from "../../../main"; + /** * CreateStatus page renders a page with tabs for general settings and contents. - * @param {string} [props.open] - Specifies the initially open tab: 'general settings' or 'content'. + * @param {object} [props.initForm] - Specifies the initial form value if the status page exists * @returns {JSX.Element} */ -const CreateStatus = ({ open = "general-settings", initForm }) => { - const theme = useTheme(); - let tabList = ["General Settings", "Contents"]; + const CreateStatus = ({ initForm }) => { + const theme = useTheme(); + const {authToken} = useSelector((state) => state.auth); + const {apiBaseUrl} = useSelector((state) => state.settings); + const [tabIdx, setTabIdx] = useState(0); const [errors, setErrors] = useState({}); const error_tab_maping = [["companyName","url","timezone","color","publish","logo"],["monitors", "showUptimePercentage", "showBarcode"]] - const [form, setForm] = useState({ - companyName: "", - url: "", - timezone: "America/Toronto", - color: "#4169E1", - //which fields matching below? - publish: false, - logo: null, - monitors: [], - showUptimePercentage: false, - showBarcode: false, - }); - const tab = open - .split("-") - .map((a) => capitalizeFirstLetter(a)) - .join(" "); + const tabList = ["General Settings", "Contents"]; + const hasInitForm = initForm && Object.keys(initForm).length > 0; + const [form, setForm] = useState( + hasInitForm + ? initForm + : { + companyName: "", + url: "", + timezone: "America/Toronto", + color: "#4169E1", + //which fields matching below? + //publish: false, + logo: null, + monitors: [], + // showUptimePercentage: false, + // showBarcode: false, + } + ); - const [tabIdx, setTabIdx] = useState(tabList.indexOf(tab)); - - const handleTabChange = (event, newTab) => { + // switch to the respective tab when there is error on it + useEffect(() => { + let newIdx = -1; + Object.keys(errors).map(id=>{ + error_tab_maping.map((val, idx) => { + let anyMatch = val.some(vl=> vl==id ) + if(anyMatch){ + newIdx = idx; + } + }) + }) + if (newIdx !== -1) setTabIdx(newIdx); + }, [errors]); + const handleTabChange = (_, newTab) => { setTabIdx(tabList.indexOf(newTab)); }; - const handleSubmit = () => { + const handleSubmit = async () => { //validate rest of the form delete form.logo; + if (hasValidationErrors(form, publicPageGeneralSettingsValidation, setErrors)) { return; } @@ -57,27 +77,21 @@ const CreateStatus = ({ open = "general-settings", initForm }) => { // logoImageValidation // ); // if (error) return; - form.logo = { ...logo, size: formatBytes(logo?.size) }; - }; - useEffect(() => { - let newIdx = -1; - Object.keys(errors).map(id=>{ - console.log("errors id") - console.log(id) - error_tab_maping.map((val, idx) => { - let anyMatch = val.some(vl=> vl==id ) - if(anyMatch){ - newIdx = idx; - } - }) - }) - console.log("newIdx") - console.log(newIdx) - if(newIdx!==-1) - setTabIdx(newIdx) - setTabIdx(tabList.indexOf(tab)); - }, [tab,errors]); + //form.logo = { ...logo, size: formatBytes(logo?.size) }; + let config = { authToken: authToken, url: apiBaseUrl, data: form }; + try{ + const res = await networkService.createStatusPage(config) + if (!res.status === 200) { + throw new Error("Failed to create status page"); + } + createToast({ body: "Status page created successfully!" }); + } + catch(e){ + createToast({ body: e.message || "Error creating status page" }); + } + + }; return ( { 0 ? initForm : form} + form={hasInitForm ? initForm : form} setForm={setForm} errors={errors} setErrors={setErrors} @@ -150,7 +164,7 @@ const CreateStatus = ({ open = "general-settings", initForm }) => { }; CreateStatus.propTypes = { - open: PropTypes.oneOf(["general-settings", "contents"]), + initForm: PropTypes.object }; export default CreateStatus; diff --git a/Client/src/Pages/Status/index.jsx b/Client/src/Pages/Status/index.jsx index 063546627..84ad6e7db 100644 --- a/Client/src/Pages/Status/index.jsx +++ b/Client/src/Pages/Status/index.jsx @@ -3,7 +3,7 @@ import Fallback from "../../Components/Fallback"; import { Box, Button, Stack } from "@mui/material"; import { useNavigate } from "react-router-dom"; import CreateStatus from "./CreateStatus"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { networkService } from "../../main"; import { useSelector } from "react-redux"; @@ -12,12 +12,14 @@ const Status = () => { const navigate = useNavigate(); const {authToken} = useSelector((state) => state.auth); const {apiBaseUrl} = useSelector((state) => state.settings); - let initForm = {} + const [initForm, setInitForm] = useState({}); useEffect(() => { const getStatusPage = async () => { let config = { authToken: authToken, url: apiBaseUrl }; - initForm = await networkService.getStatusPageByUrl(config); + let res = await networkService.getStatusPageByUrl(config); + if(res && res.data) + setInitForm( res.data.data) }; getStatusPage(); }, []); diff --git a/Client/src/Routes/index.jsx b/Client/src/Routes/index.jsx index 5fc764b6a..04e33ed8c 100644 --- a/Client/src/Routes/index.jsx +++ b/Client/src/Routes/index.jsx @@ -28,6 +28,7 @@ import CreateNewMaintenanceWindow from "../Pages/Maintenance/CreateMaintenance"; import PageSpeedDetails from "../Pages/PageSpeed/Details"; import PageSpeedConfigure from "../Pages/PageSpeed/Configure"; import withAdminCheck from "../Components/HOC/withAdminCheck"; +import CreateStatus from "../Pages/Status/CreateStatus"; const Routes = () => { const AdminCheckedRegister = withAdminCheck(Register); @@ -98,6 +99,11 @@ const Routes = () => { path="status" element={} /> + + } + /> } diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js index 7fe33845e..9049a8daa 100644 --- a/Client/src/Validation/validation.js +++ b/Client/src/Validation/validation.js @@ -154,7 +154,17 @@ const publicPageGeneralSettingsValidation = joi.object({ url: joi.string().trim().messages({ "string.empty": "URL is required." }), timezone: joi.string().trim().messages({ "string.empty": "Timezone is required." }), color: joi.string().trim().messages({ "string.empty": "Color is required." }), - publish: joi.bool() + publish: joi.bool(), + monitors: joi + .array() + .items(joi.string().pattern(/^[0-9a-fA-F]{24}$/)) + .required() + .messages({ + "string.pattern.base": "Must be a valid monitor ID", + "array.base": "Monitors must be an array", + "array.empty": "At least one monitor is required", + "any.required": "Monitors are required", + }), }