diff --git a/src/Components/Charts/DePINStatusPageBarChart/index.jsx b/src/Components/Charts/DePINStatusPageBarChart/index.jsx new file mode 100644 index 000000000..65c6278f1 --- /dev/null +++ b/src/Components/Charts/DePINStatusPageBarChart/index.jsx @@ -0,0 +1,181 @@ +// Components +import { Stack, Box, Tooltip, Typography } from "@mui/material"; + +// Utils +import { useTheme } from "@emotion/react"; +import { useState, useEffect } from "react"; +import PropTypes from "prop-types"; +import { formatDateWithTz } from "../../../Utils/timeUtils"; +import { useSelector } from "react-redux"; + +const PlaceholderCheck = ({ daysToShow }) => { + const theme = useTheme(); + + return ( + + ); +}; + +PlaceholderCheck.propTypes = { + daysToShow: PropTypes.number, +}; + +const Check = ({ check, daysToShow }) => { + const [animate, setAnimate] = useState(false); + + const theme = useTheme(); + useEffect(() => { + setAnimate(true); + }, []); + const uiTimezone = useSelector((state) => state.ui.timezone); + + return ( + + + {formatDateWithTz(check._id, "ddd, MMMM D, YYYY", uiTimezone)} + + + + + Uptime percentage + + + {check.upPercentage.toFixed(2)} + + {" "} + % + + + + + + } + placement="top" + key={`check-${check?._id}`} + slotProps={{ + popper: { + className: "bar-tooltip", + modifiers: [ + { + name: "offset", + options: { + offset: [0, -10], + }, + }, + ], + sx: { + "& .MuiTooltip-tooltip": { + backgroundColor: theme.palette.secondary.main, + border: 1, + borderColor: theme.palette.primary.lowContrast, + borderRadius: theme.shape.borderRadius, + boxShadow: theme.shape.boxShadow, + px: theme.spacing(4), + py: theme.spacing(3), + }, + "& .MuiTooltip-tooltip p": { + /* TODO Font size should point to theme */ + fontSize: 12, + color: theme.palette.secondary.contrastText, + fontWeight: 500, + }, + "& .MuiTooltip-tooltip span": { + /* TODO Font size should point to theme */ + fontSize: 11, + color: theme.palette.secondary.contrastText, + fontWeight: 600, + }, + }, + }, + }} + > + + + + + ); +}; + +Check.propTypes = { + check: PropTypes.object, + daysToShow: PropTypes.number, +}; + +const DePINStatusPageBarChart = ({ checks = [], daysToShow = 30 }) => { + if (checks.length !== daysToShow) { + const placeholders = Array(daysToShow - checks.length).fill("placeholder"); + checks = [...checks, ...placeholders]; + } + return ( + + {checks.map((check) => { + if (check === "placeholder") { + return ( + + ); + } + return ( + + ); + })} + + ); +}; + +DePINStatusPageBarChart.propTypes = { + checks: PropTypes.array, + daysToShow: PropTypes.number, +}; + +export default DePINStatusPageBarChart; diff --git a/src/Pages/DistributedUptimeStatus/Status/Components/MonitorsList/index.jsx b/src/Pages/DistributedUptimeStatus/Status/Components/MonitorsList/index.jsx new file mode 100644 index 000000000..d9ed16e63 --- /dev/null +++ b/src/Pages/DistributedUptimeStatus/Status/Components/MonitorsList/index.jsx @@ -0,0 +1,66 @@ +// Components +import { Stack, Box } from "@mui/material"; +import Host from "../../../../../Components/Host"; +import DePINStatusPageBarChart from "../../../../../Components/Charts/DePINStatusPageBarChart"; +import { StatusLabel } from "../../../../../Components/Label"; + +//Utils +import { useTheme } from "@mui/material/styles"; +import useUtils from "../../../../Uptime/Monitors/Hooks/useUtils"; +import PropTypes from "prop-types"; +const MonitorsList = ({ + isLoading = false, + shouldRender = true, + monitors = [], + timeFrame, +}) => { + const theme = useTheme(); + const { determineState } = useUtils(); + return ( + <> + {monitors?.map((monitor) => { + const status = determineState(monitor); + return ( + + + + + + + + + + + + ); + })} + + ); +}; + +MonitorsList.propTypes = { + monitors: PropTypes.array.isRequired, +}; + +export default MonitorsList; diff --git a/src/Pages/DistributedUptimeStatus/Status/Components/TimeframeHeader/index.jsx b/src/Pages/DistributedUptimeStatus/Status/Components/TimeframeHeader/index.jsx new file mode 100644 index 000000000..011f470aa --- /dev/null +++ b/src/Pages/DistributedUptimeStatus/Status/Components/TimeframeHeader/index.jsx @@ -0,0 +1,39 @@ +import { Stack, Button, ButtonGroup } from "@mui/material"; +import { RowContainer } from "../../../../../Components/StandardContainer"; +import { useTheme } from "@emotion/react"; + +const TimeFrameHeader = ({ timeFrame, setTimeFrame }) => { + const theme = useTheme(); + return ( + + + + + + + + ); +}; + +export default TimeFrameHeader; diff --git a/src/Pages/DistributedUptimeStatus/Status/Hooks/useStatusPageFetchByUrl.jsx b/src/Pages/DistributedUptimeStatus/Status/Hooks/useStatusPageFetchByUrl.jsx index 0ca6346a0..61c4f1b65 100644 --- a/src/Pages/DistributedUptimeStatus/Status/Hooks/useStatusPageFetchByUrl.jsx +++ b/src/Pages/DistributedUptimeStatus/Status/Hooks/useStatusPageFetchByUrl.jsx @@ -2,25 +2,41 @@ import { useState, useEffect } from "react"; import { networkService } from "../../../../main"; import { createToast } from "../../../../Utils/toastUtils"; import { useSelector } from "react-redux"; +import { useTheme } from "@emotion/react"; +import { useMonitorUtils } from "../../../../Hooks/useMonitorUtils"; -const useStatusPageFetchByUrl = ({ url }) => { +const useStatusPageFetchByUrl = ({ url, timeFrame }) => { const [isLoading, setIsLoading] = useState(true); const [networkError, setNetworkError] = useState(false); const [statusPage, setStatusPage] = useState(undefined); const [monitorId, setMonitorId] = useState(undefined); const [isPublished, setIsPublished] = useState(false); const { authToken } = useSelector((state) => state.auth); + const theme = useTheme(); + const { getMonitorWithPercentage } = useMonitorUtils(); + useEffect(() => { const fetchStatusPageByUrl = async () => { try { - const response = await networkService.getStatusPageByUrl({ + const response = await networkService.getDistributedStatusPageByUrl({ authToken, url, type: "distributed", + timeFrame, }); if (!response?.data?.data) return; const statusPage = response.data.data; - setStatusPage(statusPage); + + const monitorsWithPercentage = statusPage?.subMonitors.map((monitor) => + getMonitorWithPercentage(monitor, theme) + ); + + const statusPageWithSubmonitorPercentages = { + ...statusPage, + subMonitors: monitorsWithPercentage, + }; + setStatusPage(statusPageWithSubmonitorPercentages); + setMonitorId(statusPage?.monitors[0]); setIsPublished(statusPage?.isPublished); } catch (error) { @@ -33,7 +49,7 @@ const useStatusPageFetchByUrl = ({ url }) => { } }; fetchStatusPageByUrl(); - }, [authToken, url]); + }, [authToken, url, getMonitorWithPercentage, theme, timeFrame]); return [isLoading, networkError, statusPage, monitorId, isPublished]; }; diff --git a/src/Pages/DistributedUptimeStatus/Status/index.jsx b/src/Pages/DistributedUptimeStatus/Status/index.jsx index dce15ca5c..f26133898 100644 --- a/src/Pages/DistributedUptimeStatus/Status/index.jsx +++ b/src/Pages/DistributedUptimeStatus/Status/index.jsx @@ -16,7 +16,7 @@ import UptLogo from "../../../assets/icons/upt_logo.png"; import PeopleAltOutlinedIcon from "@mui/icons-material/PeopleAltOutlined"; import InfoBox from "../../../Components/InfoBox"; import StatusHeader from "../../DistributedUptime/Details/Components/StatusHeader"; -import MonitorsList from "../../StatusPage/Status/Components/MonitorsList"; +import MonitorsList from "./Components/MonitorsList"; //Utils import { useTheme } from "@mui/material/styles"; @@ -27,6 +27,7 @@ import { useStatusPageFetchByUrl } from "./Hooks/useStatusPageFetchByUrl"; import { useStatusPageDelete } from "../../StatusPage/Status/Hooks/useStatusPageDelete"; import { useNavigate } from "react-router-dom"; import { useLocation } from "react-router-dom"; +import TimeFrameHeader from "./Components/TimeframeHeader"; const DistributedUptimeStatus = () => { const { url } = useParams(); @@ -37,6 +38,7 @@ const DistributedUptimeStatus = () => { // Local State const [dateRange, setDateRange] = useState("day"); const [isDeleteOpen, setIsDeleteOpen] = useState(false); + const [timeFrame, setTimeFrame] = useState(30); // Utils const theme = useTheme(); const navigate = useNavigate(); @@ -49,6 +51,7 @@ const DistributedUptimeStatus = () => { isPublished, ] = useStatusPageFetchByUrl({ url, + timeFrame, }); const [isLoading, networkError, connectionStatus, monitor, lastUpdateTrigger] = @@ -217,7 +220,14 @@ const DistributedUptimeStatus = () => { monitor={monitor} lastUpdateTrigger={lastUpdateTrigger} /> - + +