diff --git a/Client/src/Components/Fallback/index.jsx b/Client/src/Components/Fallback/index.jsx index 36c0d3eb1..3e30cd374 100644 --- a/Client/src/Components/Fallback/index.jsx +++ b/Client/src/Components/Fallback/index.jsx @@ -27,7 +27,6 @@ const Fallback = ({ title, checks, link = "/", isAdmin, vowelStart = false }) => return ( { + const location = useLocation(); + const isCreate = location.pathname.startsWith("/distributed-uptime/create"); + // Redux state const { user, authToken } = useSelector((state) => state.auth); const isLoading = useSelector((state) => state.uptimeMonitors.isLoading); @@ -103,7 +107,6 @@ const CreateDistributedUptime = () => { { [name]: value }, { abortEarly: false } ); - console.log(name); setErrors((prev) => ({ ...prev, ...(error ? { [name]: error.details[0].message } : { [name]: undefined }), diff --git a/Client/src/Pages/DistributedUptime/Details/index.jsx b/Client/src/Pages/DistributedUptime/Details/index.jsx index 27a596af4..9915e1811 100644 --- a/Client/src/Pages/DistributedUptime/Details/index.jsx +++ b/Client/src/Pages/DistributedUptime/Details/index.jsx @@ -74,7 +74,7 @@ const DistributedUptimeDetails = () => { { const theme = useTheme(); - const { monitorId } = useParams(); + const { monitorId, url } = useParams(); const navigate = useNavigate(); const location = useLocation(); - const isCreate = location.pathname.startsWith("/distributed-uptime/status/create"); + const isCreate = location.pathname.startsWith("/status/distributed/create"); const [createStatusPage, isLoading, networkError] = useCreateStatusPage(isCreate); + + const [statusPage, statusPageMonitors, statusPageIsLoading, statusPageNetworkError] = + useStatusPageFetch(isCreate, url); + const BREADCRUMBS = [ { name: "distributed uptime", path: "/distributed-uptime" }, { name: "details", path: `/distributed-uptime/${monitorId}` }, - { name: "create status page", path: `` }, + { name: isCreate ? "create status page" : "edit status page", path: `` }, ]; // Local state const [form, setForm] = useState({ + type: "distributed", isPublished: false, - url: Math.floor(Math.random() * 1000000).toFixed(0), + url: url ?? Math.floor(Math.random() * 1000000).toFixed(0), logo: undefined, companyName: "", monitors: [monitorId], @@ -87,8 +93,9 @@ const CreateStatus = () => { if (typeof error === "undefined") { const success = await createStatusPage({ form: formToSubmit }); if (success) { - createToast({ body: "Status page created successfully" }); - navigate(`/distributed-uptime/status/${form.url}`); + const verb = isCreate ? "created" : "updated"; + createToast({ body: `Status page ${verb} successfully` }); + navigate(`/status/distributed/${form.url}`); } return; } @@ -99,6 +106,36 @@ const CreateStatus = () => { setErrors((prev) => ({ ...prev, ...newErrors })); }; + // If we are configuring, populate fields + useEffect(() => { + if (isCreate) return; + if (typeof statusPage === "undefined") { + return; + } + + let newLogo = undefined; + if (statusPage.logo) { + newLogo = { + src: `data:${statusPage.logo.contentType};base64,${statusPage.logo.data}`, + name: "logo", + type: statusPage.logo.contentType, + size: null, + }; + } + + setForm((prev) => { + return { + ...prev, + companyName: statusPage?.companyName, + isPublished: statusPage?.isPublished, + timezone: statusPage?.timezone, + monitors: statusPageMonitors.map((monitor) => monitor._id), + color: statusPage?.color, + logo: newLogo, + }; + }); + }, [isCreate, statusPage, statusPageMonitors]); + return ( @@ -159,6 +196,7 @@ const CreateStatus = () => { name="url" type="url" label="Your status page address" + disabled={!isCreate} value={form.url} onChange={handleFormChange} helperText={errors["url"]} diff --git a/Client/src/Pages/DistributedUptime/Status/Components/Skeleton/index.jsx b/Client/src/Pages/DistributedUptimeStatus/Status/Components/Skeleton/index.jsx similarity index 100% rename from Client/src/Pages/DistributedUptime/Status/Components/Skeleton/index.jsx rename to Client/src/Pages/DistributedUptimeStatus/Status/Components/Skeleton/index.jsx diff --git a/Client/src/Pages/DistributedUptime/Status/Hooks/useStatusPageFetchByUrl.jsx b/Client/src/Pages/DistributedUptimeStatus/Status/Hooks/useStatusPageFetchByUrl.jsx similarity index 90% rename from Client/src/Pages/DistributedUptime/Status/Hooks/useStatusPageFetchByUrl.jsx rename to Client/src/Pages/DistributedUptimeStatus/Status/Hooks/useStatusPageFetchByUrl.jsx index 583fed69d..0ca6346a0 100644 --- a/Client/src/Pages/DistributedUptime/Status/Hooks/useStatusPageFetchByUrl.jsx +++ b/Client/src/Pages/DistributedUptimeStatus/Status/Hooks/useStatusPageFetchByUrl.jsx @@ -13,7 +13,11 @@ const useStatusPageFetchByUrl = ({ url }) => { useEffect(() => { const fetchStatusPageByUrl = async () => { try { - const response = await networkService.getStatusPageByUrl({ authToken, url }); + const response = await networkService.getStatusPageByUrl({ + authToken, + url, + type: "distributed", + }); if (!response?.data?.data) return; const statusPage = response.data.data; setStatusPage(statusPage); diff --git a/Client/src/Pages/DistributedUptime/Status/index.jsx b/Client/src/Pages/DistributedUptimeStatus/Status/index.jsx similarity index 85% rename from Client/src/Pages/DistributedUptime/Status/index.jsx rename to Client/src/Pages/DistributedUptimeStatus/Status/index.jsx index d91761e06..89f97a4d0 100644 --- a/Client/src/Pages/DistributedUptime/Status/index.jsx +++ b/Client/src/Pages/DistributedUptimeStatus/Status/index.jsx @@ -1,12 +1,12 @@ //Components -import DistributedUptimeMap from "../Details/Components/DistributedUptimeMap"; +import DistributedUptimeMap from "../../DistributedUptime/Details/Components/DistributedUptimeMap"; import Breadcrumbs from "../../../Components/Breadcrumbs"; import { Stack, Typography } from "@mui/material"; -import DeviceTicker from "../Details/Components/DeviceTicker"; -import DistributedUptimeResponseChart from "../Details/Components/DistributedUptimeResponseChart"; -import NextExpectedCheck from "../Details/Components/NextExpectedCheck"; -import Footer from "../Details/Components/Footer"; -import StatBoxes from "../Details/Components/StatBoxes"; +import DeviceTicker from "../../DistributedUptime/Details/Components/DeviceTicker"; +import DistributedUptimeResponseChart from "../../DistributedUptime/Details/Components/DistributedUptimeResponseChart"; +import NextExpectedCheck from "../../DistributedUptime/Details/Components/NextExpectedCheck"; +import Footer from "../../DistributedUptime/Details/Components/Footer"; +import StatBoxes from "../../DistributedUptime/Details/Components/StatBoxes"; import ControlsHeader from "../../StatusPage/Status/Components/ControlsHeader"; import MonitorTimeFrameHeader from "../../../Components/MonitorTimeFrameHeader"; import GenericFallback from "../../../Components/GenericFallback"; @@ -16,7 +16,7 @@ import SkeletonLayout from "./Components/Skeleton"; import { useTheme } from "@mui/material/styles"; import { useState } from "react"; import { useParams } from "react-router-dom"; -import { useSubscribeToDetails } from "../Details/Hooks/useSubscribeToDetails"; +import { useSubscribeToDetails } from "../../DistributedUptime/Details/Hooks/useSubscribeToDetails"; import { useStatusPageFetchByUrl } from "./Hooks/useStatusPageFetchByUrl"; import { useStatusPageDelete } from "../../StatusPage/Status/Hooks/useStatusPageDelete"; import { useNavigate } from "react-router-dom"; @@ -24,7 +24,7 @@ import { useLocation } from "react-router-dom"; const DistributedUptimeStatus = () => { const { url } = useParams(); const location = useLocation(); - const isPublic = location.pathname.startsWith("/distributed-uptime/status/public"); + const isPublic = location.pathname.startsWith("/status/distributed/public"); // Local State const [dateRange, setDateRange] = useState("day"); @@ -84,7 +84,7 @@ const DistributedUptimeStatus = () => { } // Done loading, a status page exists but is not public - if (!statusPageIsLoading && statusPage.isPublished === false) { + if (!statusPageIsLoading && isPublic && statusPage.isPublished === false) { return ( @@ -141,6 +141,8 @@ const DistributedUptimeStatus = () => { isDeleting={isDeleting} isDeleteOpen={isDeleteOpen} setIsDeleteOpen={setIsDeleteOpen} + url={url} + type="distributed" /> @@ -128,6 +129,7 @@ const TabSettings = ({ }; TabSettings.propTypes = { + isCreate: PropTypes.bool, tabValue: PropTypes.string, form: PropTypes.object, handleFormChange: PropTypes.func, diff --git a/Client/src/Pages/StatusPage/Create/Components/Tabs/index.jsx b/Client/src/Pages/StatusPage/Create/Components/Tabs/index.jsx index 87e18ed4d..11f6b4f9a 100644 --- a/Client/src/Pages/StatusPage/Create/Components/Tabs/index.jsx +++ b/Client/src/Pages/StatusPage/Create/Components/Tabs/index.jsx @@ -8,6 +8,7 @@ import Content from "./Content"; import PropTypes from "prop-types"; const Tabs = ({ + isCreate, form, errors, monitors, @@ -47,6 +48,7 @@ const Tabs = ({ progress={progress} removeLogo={removeLogo} errors={errors} + isCreate={isCreate} /> ) : ( { +const useCreateStatusPage = (isCreate, url) => { const { authToken, user } = useSelector((state) => state.auth); const [isLoading, setIsLoading] = useState(false); @@ -11,7 +11,7 @@ const useCreateStatusPage = (isCreate) => { const createStatusPage = async ({ form }) => { setIsLoading(true); try { - await networkService.createStatusPage({ authToken, user, form, isCreate }); + await networkService.createStatusPage({ authToken, user, form, isCreate, url }); return true; } catch (error) { setNetworkError(true); diff --git a/Client/src/Pages/StatusPage/Create/index.jsx b/Client/src/Pages/StatusPage/Create/index.jsx index 58269e3b8..158aca2e9 100644 --- a/Client/src/Pages/StatusPage/Create/index.jsx +++ b/Client/src/Pages/StatusPage/Create/index.jsx @@ -14,6 +14,7 @@ import { createToast } from "../../../Utils/toastUtils"; import { useNavigate } from "react-router-dom"; import { useLocation } from "react-router-dom"; import { useStatusPageFetch } from "../Status/Hooks/useStatusPageFetch"; +import { useParams } from "react-router-dom"; //Constants const TAB_LIST = ["General settings", "Contents"]; @@ -24,16 +25,18 @@ const ERROR_TAB_MAPPING = [ ]; const CreateStatusPage = () => { + const { url } = useParams(); //Local state const [tab, setTab] = useState(0); const [progress, setProgress] = useState({ value: 0, isLoading: false }); const [form, setForm] = useState({ isPublished: false, companyName: "", - url: "/status/public", + url: url ?? Math.floor(Math.random() * 1000000).toFixed(0), logo: undefined, timezone: "America/Toronto", color: "#4169E1", + type: "uptime", monitors: [], showCharts: true, showUptimePercentage: true, @@ -45,7 +48,7 @@ const CreateStatusPage = () => { // Setup const location = useLocation(); - const isCreate = location.pathname === "/status/create"; + const isCreate = location.pathname === "/status/uptime/create"; //Utils const theme = useTheme(); @@ -53,8 +56,9 @@ const CreateStatusPage = () => { const [createStatusPage, createStatusIsLoading, createStatusPageNetworkError] = useCreateStatusPage(isCreate); const navigate = useNavigate(); + const [statusPage, statusPageMonitors, statusPageIsLoading, statusPageNetworkError] = - useStatusPageFetch(isCreate); + useStatusPageFetch(isCreate, url); // Handlers const handleFormChange = (e) => { @@ -131,7 +135,7 @@ const CreateStatusPage = () => { const success = await createStatusPage({ form }); if (success) { createToast({ body: "Status page created successfully" }); - navigate("/status"); + navigate(`/status/uptime/${form.url}`); } return; } @@ -141,7 +145,6 @@ const CreateStatusPage = () => { newErrors[err.path[0]] = err.message; }); setErrors((prev) => ({ ...prev, ...newErrors })); - const errorTabs = Object.keys(newErrors).map((err) => { return ERROR_TAB_MAPPING.findIndex((tab) => tab.includes(err)); }); @@ -150,6 +153,13 @@ const CreateStatusPage = () => { if (errorTabs.some((errorTab) => errorTab === tab)) { return; } + + // If we get -1, there's an unknown error + if (errorTabs[0] === -1) { + createToast({ body: "Unknown error" }); + return; + } + // Otherwise go to tab with error setTab(errorTabs[0]); }; @@ -218,6 +228,7 @@ const CreateStatusPage = () => { tab={tab} setTab={setTab} TAB_LIST={TAB_LIST} + isCreate={isCreate} /> { +const Controls = ({ isDeleteOpen, setIsDeleteOpen, isDeleting, url, type }) => { const theme = useTheme(); const location = useLocation(); const currentPath = location.pathname; const navigate = useNavigate(); - if (currentPath === "/status/public") { + if (currentPath.startsWith("/status/uptime/public")) { return null; } - if (currentPath.startsWith("/distributed-uptime/status/public")) { + if (currentPath.startsWith("/status/distributed/public")) { return null; } @@ -42,7 +42,13 @@ const Controls = ({ isDeleteOpen, setIsDeleteOpen, isDeleting }) => {