diff --git a/Client/src/Components/Charts/ChartUtils.js b/Client/src/Components/Charts/ChartUtils.js
new file mode 100644
index 000000000..a2c0faa9d
--- /dev/null
+++ b/Client/src/Components/Charts/ChartUtils.js
@@ -0,0 +1,45 @@
+const RANGE_MAX = 100;
+const RANGE_MIN = 1;
+
+const calculatePercentile = (arr, percentile) => {
+ const sorted = arr.slice().sort((a, b) => a.responseTime - b.responseTime);
+ const index = (percentile / 100) * (sorted.length - 1);
+ const lower = Math.floor(index);
+ const upper = lower + 1;
+ const weight = index % 1;
+ if (upper >= sorted.length) return sorted[lower].responseTime;
+ return (
+ sorted[lower].responseTime * (1 - weight) +
+ sorted[upper].responseTime * weight
+ );
+};
+
+export const NormalizeData = (checks) => {
+ if (checks.length > 1) {
+ // Get the 5th and 95th percentile
+ const min = calculatePercentile(checks, 5);
+ const max = calculatePercentile(checks, 95);
+
+ const normalizedChecks = checks.map((check) => {
+ // Normalize the response time between 1 and 100
+ let normalizedResponseTime =
+ RANGE_MIN +
+ ((check.responseTime - min) * (RANGE_MAX - RANGE_MIN)) / (max - min);
+
+ // Put a floor on the response times so we don't have extreme outliers
+ // Better visuals
+ normalizedResponseTime = Math.max(
+ RANGE_MIN,
+ Math.min(RANGE_MAX, normalizedResponseTime)
+ );
+ return {
+ ...check,
+ responseTime: normalizedResponseTime,
+ };
+ });
+
+ return normalizedChecks;
+ } else {
+ return checks;
+ }
+};
diff --git a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.css b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
new file mode 100644
index 000000000..2b5074ccb
--- /dev/null
+++ b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
@@ -0,0 +1,69 @@
+import PropTypes from "prop-types";
+import {
+ AreaChart,
+ Area,
+ XAxis,
+ CartesianGrid,
+ Tooltip,
+ ResponsiveContainer,
+} from "recharts";
+import { NormalizeData } from "../ChartUtils";
+
+const MonitorDetailsAreaChart = ({ checks }) => {
+ // SQUASH ERROR, NOT PERMANENT SOLUTION
+ const error = console.error;
+ console.error = (...args) => {
+ if (/defaultProps/.test(args[0])) return;
+ error(...args);
+ };
+
+ // END SQUASH ERROR, NOT PERMANENT SOLUTION
+
+ const formatDate = (timestamp) => {
+ const date = new Date(timestamp);
+ return date.toLocaleTimeString("en-US", {
+ hour: "numeric",
+ minute: "2-digit",
+ hour12: true,
+ });
+ };
+
+ let normalizedChecks = [];
+ if (checks && checks.length > 0) {
+ normalizedChecks = NormalizeData(checks);
+ }
+
+ return (
+