Files
Checkmate/Client/src/Pages/DistributedUptime/Details/index.jsx
2025-02-05 14:58:21 -08:00

326 lines
8.7 KiB
JavaScript

//Components
import DistributedUptimeMap from "./Components/DistributedUptimeMap";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import { Stack, Typography, Box, Button, ButtonGroup } from "@mui/material";
import ChartBox from "../../../Components/Charts/ChartBox";
import StatBox from "../../../Components/StatBox";
import ResponseTimeIcon from "../../../assets/icons/response-time-icon.svg?react";
import DeviceTicker from "./Components/DeviceTicker";
import DistributedUptimeResponseChart from "./Components/DistributedUptimeResponseChart";
import UptLogo from "../../../assets/icons/upt_logo.png";
import LastUpdate from "./Components/LastUpdate";
import NextExpectedCheck from "./Components/NextExpectedCheck";
import Footer from "./Components/Footer";
//Utils
import { networkService } from "../../../main";
import { useSelector } from "react-redux";
import { useTheme } from "@mui/material/styles";
import { useEffect, useState, useCallback, useRef } from "react";
import { useParams } from "react-router-dom";
//Constants
const BASE_BOX_PADDING_VERTICAL = 8;
const BASE_BOX_PADDING_HORIZONTAL = 8;
const MAX_RETRIES = 10;
const RETRY_DELAY = 5000;
function getRandomDevice() {
const manufacturers = {
Apple: ["iPhone 15 Pro Max", "iPhone 15", "iPhone 14 Pro", "iPhone 14", "iPhone 13"],
Samsung: [
"Galaxy S23 Ultra",
"Galaxy S23+",
"Galaxy S23",
"Galaxy Z Fold5",
"Galaxy Z Flip5",
],
Google: ["Pixel 8 Pro", "Pixel 8", "Pixel 7a", "Pixel 7", "Pixel 6a"],
OnePlus: [
"OnePlus 11",
"OnePlus 10T",
"OnePlus Nord 3",
"OnePlus 10 Pro",
"OnePlus Nord 2T",
],
Xiaomi: ["13 Pro", "13", "Redmi Note 12", "POCO F5", "Redmi 12"],
Huawei: ["P60 Pro", "Mate X3", "Nova 11", "P50 Pro", "Mate 50"],
Sony: ["Xperia 1 V", "Xperia 5 V", "Xperia 10 V", "Xperia Pro-I", "Xperia 1 IV"],
Motorola: ["Edge 40 Pro", "Edge 40", "G84", "G54", "Razr 40 Ultra"],
ASUS: [
"ROG Phone 7",
"Zenfone 10",
"ROG Phone 6",
"Zenfone 9",
"ROG Phone 7 Ultimate",
],
};
const manufacturerNames = Object.keys(manufacturers);
const randomManufacturer =
manufacturerNames[Math.floor(Math.random() * manufacturerNames.length)];
const models = manufacturers[randomManufacturer];
const randomModel = models[Math.floor(Math.random() * models.length)];
return {
manufacturer: randomManufacturer,
model: randomModel,
};
}
// export const StatBox = ({ heading, value, img, altTxt }) => {
// const theme = useTheme();
// return (
// <Stack
// direction="row"
// width={"25%"}
// justifyContent="center"
// sx={{
// padding: `${theme.spacing(BASE_BOX_PADDING_VERTICAL)} ${theme.spacing(BASE_BOX_PADDING_HORIZONTAL)}`,
// backgroundColor: theme.palette.background.main,
// border: 1,
// borderStyle: "solid",
// borderColor: theme.palette.primary.lowContrast,
// }}
// >
// {img && (
// <img
// style={{ marginRight: theme.spacing(8) }}
// height={30}
// width={30}
// src={img}
// alt={altTxt}
// />
// )}
// <Stack direction="column">
// <Typography variant="h2">{heading}</Typography>
// <Typography>{value}</Typography>
// </Stack>
// </Stack>
// );
// };
const DistributedUptimeDetails = () => {
// Redux State
const { authToken } = useSelector((state) => state.auth);
const { mode } = useSelector((state) => state.ui);
// Local State
// const [hoveredUptimeData, setHoveredUptimeData] = useState(null);
// const [hoveredIncidentsData, setHoveredIncidentsData] = useState(null);
const [retryCount, setRetryCount] = useState(0);
const [connectionStatus, setConnectionStatus] = useState("down");
const [lastUpdateTrigger, setLastUpdateTrigger] = useState(Date.now());
const [dateRange, setDateRange] = useState("day");
const [monitor, setMonitor] = useState(null);
const [devices, setDevices] = useState([]);
// Refs
const prevDateRangeRef = useRef(dateRange);
// Utils
const theme = useTheme();
const { monitorId } = useParams();
// Constants
const BREADCRUMBS = [
{ name: "Distributed Uptime", path: "/distributed-uptime" },
{ name: "Details", path: `/distributed-uptime/${monitorId}` },
];
useEffect(() => {
const hasDateRangeChanged = prevDateRangeRef.current !== dateRange;
prevDateRangeRef.current = dateRange; // Update the ref to the current dateRange
if (!hasDateRangeChanged) {
setDevices(Array.from({ length: 5 }, getRandomDevice));
}
}, [dateRange]);
const connectToService = useCallback(() => {
return networkService.subscribeToDistributedUptimeDetails({
authToken,
monitorId,
dateRange: dateRange,
normalize: true,
onUpdate: (data) => {
setLastUpdateTrigger(Date.now());
const latestChecksWithDevice = data?.monitor?.latestChecks.map((check, idx) => {
check.device = devices[idx];
return check;
});
const monitorWithDevice = {
...data.monitor,
latestChecks: latestChecksWithDevice,
};
setMonitor(monitorWithDevice);
},
onOpen: () => {
setConnectionStatus("up");
setRetryCount(0); // Reset retry count on successful connection
},
onError: () => {
setConnectionStatus("down");
console.log("Error, attempting reconnect...");
if (retryCount < MAX_RETRIES) {
setTimeout(() => {
setRetryCount((prev) => prev + 1);
connectToService();
}, RETRY_DELAY);
} else {
console.log("Max retries reached");
}
},
});
}, [authToken, monitorId, dateRange, retryCount, devices]);
useEffect(() => {
const devices = Array.from({ length: 5 }, getRandomDevice);
const cleanup = connectToService(devices);
return cleanup;
}, [connectToService]);
return (
monitor && (
<Stack
direction="column"
gap={theme.spacing(8)}
>
<Breadcrumbs list={BREADCRUMBS} />
{monitor?.url !== "https://jup.ag/" &&
monitor?.url !== "https://explorer.solana.com/" && (
<Box>
<Typography
component="h1"
variant="h1"
>
{monitor.name}
</Typography>
</Box>
)}
<Stack
direction="row"
alignItems="center"
gap={theme.spacing(8)}
>
<Typography variant="h2">
Distributed Uptime Monitoring powered by DePIN
</Typography>
</Stack>
<Stack
direction="row"
gap={theme.spacing(8)}
>
<StatBox
heading="Avg Response Time"
subHeading={`${Math.floor(monitor?.avgResponseTime ?? 0)} ms`}
/>
<StatBox
heading="Checking every"
subHeading={`${(monitor?.interval ?? 0) / 1000} seconds`}
/>
<StatBox
heading={"Last check"}
subHeading={
<LastUpdate
lastUpdateTime={monitor?.timeSinceLastCheck ?? 0}
suffix={"seconds ago"}
/>
}
/>
<StatBox
heading="Last server push"
subHeading={
<LastUpdate
suffix={"seconds ago"}
lastUpdateTime={0}
trigger={lastUpdateTrigger}
/>
}
/>
<StatBox
heading="UPT Burned"
subHeading={monitor?.totalUptBurnt ?? 0}
img={UptLogo}
alt="Upt Logo"
/>
</Stack>
<Box sx={{ width: "100%" }}>
<NextExpectedCheck
lastUpdateTime={monitor?.timeSinceLastCheck ?? 0}
interval={monitor?.interval ?? 0}
trigger={lastUpdateTrigger}
/>
</Box>
<Stack
direction="row"
justifyContent="space-between"
alignItems="flex-end"
gap={theme.spacing(4)}
mb={theme.spacing(8)}
>
<Typography variant="body2">
Showing statistics for past{" "}
{dateRange === "day"
? "24 hours"
: dateRange === "week"
? "7 days"
: "30 days"}
.
</Typography>
<ButtonGroup sx={{ height: 32 }}>
<Button
variant="group"
filled={(dateRange === "day").toString()}
onClick={() => setDateRange("day")}
>
Day
</Button>
<Button
variant="group"
filled={(dateRange === "week").toString()}
onClick={() => setDateRange("week")}
>
Week
</Button>
<Button
variant="group"
filled={(dateRange === "month").toString()}
onClick={() => setDateRange("month")}
>
Month
</Button>
</ButtonGroup>
</Stack>
<ChartBox
icon={<ResponseTimeIcon />}
header="Response Times"
sx={{ padding: 0 }}
>
<DistributedUptimeResponseChart checks={monitor?.groupedChecks ?? []} />
</ChartBox>
<Stack
direction="row"
gap={theme.spacing(8)}
>
<DistributedUptimeMap
checks={monitor?.groupedMapChecks ?? []}
height={"100%"}
width={"100%"}
/>
<DeviceTicker
width={"25vw"}
data={monitor?.latestChecks ?? []}
connectionStatus={connectionStatus}
/>
</Stack>
<Footer />
</Stack>
)
);
};
export default DistributedUptimeDetails;