diff --git a/Client/src/App.jsx b/Client/src/App.jsx
index 7dd1404a1..a6581ad81 100644
--- a/Client/src/App.jsx
+++ b/Client/src/App.jsx
@@ -18,8 +18,10 @@ import CheckEmail from "./Pages/CheckEmail";
import SetNewPassword from "./Pages/SetNewPassword";
import NewPasswordConfirmed from "./Pages/NewPasswordConfirmed";
import ProtectedRoute from "./Components/ProtectedRoute";
+import Details from "./Pages/Details";
import Maintenance from "./Pages/Maintenance";
+
function App() {
return (
<>
@@ -42,6 +44,10 @@ function App() {
path="incidents"
element={}
/>
+ }
+ />
}
diff --git a/Client/src/Components/CustomizedTables/index.css b/Client/src/Components/CustomizedTables/index.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/Client/src/Components/CustomizedTables/index.jsx b/Client/src/Components/CustomizedTables/index.jsx
new file mode 100644
index 000000000..2630d5671
--- /dev/null
+++ b/Client/src/Components/CustomizedTables/index.jsx
@@ -0,0 +1,152 @@
+import { styled, useTheme } from '@mui/material/styles';
+import Table from '@mui/material/Table';
+import TableBody from '@mui/material/TableBody';
+import TableCell, { tableCellClasses } from '@mui/material/TableCell';
+import TableContainer from '@mui/material/TableContainer';
+import TableHead from '@mui/material/TableHead';
+import TableRow from '@mui/material/TableRow';
+import Paper from '@mui/material/Paper';
+import Box from '@mui/material/Box';
+import Typography from '@mui/material/Typography';
+import { StatusLabel } from "../../Components/Label/";
+import PropTypes from 'prop-types';
+
+const StyledTableCell = styled(TableCell)(({ theme }) => ({
+ [`&.${tableCellClasses.head}`]: {
+ backgroundColor: theme.palette.action.hover,
+ color: theme.palette.common.black,
+ },
+ [`&.${tableCellClasses.body}`]: {
+ fontSize: 14,
+ },
+}));
+
+const StyledTableRow = styled(TableRow)(({ theme }) => ({
+ '&:nth-of-type(odd)': {
+ backgroundColor: theme.palette.action.hover,
+ },
+ '&:nth-of-type(even)': {
+ backgroundColor: theme.palette.common.white,
+ },
+ '&:last-child td, &:last-child th': {
+ border: 0,
+ },
+}));
+
+function createData(name, date, message) {
+ return { name, date, message };
+}
+
+const CustomizedTables = ({ monitor }) => {
+ const theme = useTheme();
+
+ const rows = (monitor && monitor.checks) ? monitor.checks.map(check => createData(
+ ,
+ new Date(check.createdAt).toLocaleString(),
+ `HTTP ${check.statusCode} - ${check.status ? 'OK' : 'NOK'}`
+ )) : [];
+
+ return (
+
+
+ {[...Array(4)].map((_, index) => (
+
+
+ Currently up for
+
+
+ 4h 30m 2s
+
+
+ ))}
+
+
+
+ History
+
+
+
+
+
+
+ Status
+ Date & Time
+ Message
+
+
+
+ {rows.map((row) => (
+
+
+ {row.name}
+
+ {row.date}
+ {row.message}
+
+ ))}
+
+
+
+
+ );
+};
+
+CustomizedTables.propTypes = {
+ monitor: PropTypes.shape({
+ checks: PropTypes.arrayOf(
+ PropTypes.shape({
+ status: PropTypes.bool.isRequired,
+ createdAt: PropTypes.string.isRequired,
+ statusCode: PropTypes.number.isRequired,
+ })
+ ),
+ }),
+};
+
+CustomizedTables.defaultProps = {
+ monitor: { checks: [] },
+};
+
+export default CustomizedTables;
diff --git a/Client/src/Pages/Details/index.css b/Client/src/Pages/Details/index.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/Client/src/Pages/Details/index.jsx b/Client/src/Pages/Details/index.jsx
new file mode 100644
index 000000000..c257077c1
--- /dev/null
+++ b/Client/src/Pages/Details/index.jsx
@@ -0,0 +1,163 @@
+import React from 'react';
+import CustomizedTables from '../../Components/CustomizedTables';
+import { Box, Typography, useTheme } from '@mui/material';
+
+/**
+ * Details page component displaying monitor details and related information.
+ * @component
+ */
+const DetailsPage = () => {
+ const theme = useTheme();
+
+ // Example monitor data (replace with actual data or fetch from API)
+ const monitorData = {
+ "_id": "66863aa2437936b46e225d1f",
+ "userId": "66863a8f437936b46e225d1a",
+ "name": "Google",
+ "description": "Google",
+ "status": false,
+ "type": "http",
+ "url": "https://www.google.com/404",
+ "isActive": true,
+ "interval": 60000,
+ "createdAt": "2024-07-04T06:01:06.527Z",
+ "updatedAt": "2024-07-04T06:02:00.250Z",
+ "__v": 0,
+ "checks": [
+ {
+ "_id": "66863ad8437936b46e225d6d",
+ "monitorId": "66863aa2437936b46e225d1f",
+ "status": false,
+ "responseTime": 144,
+ "expiry": "2024-07-04T06:02:00.247Z",
+ "statusCode": 404,
+ "createdAt": "2024-07-04T06:02:00.248Z",
+ "updatedAt": "2024-07-04T06:02:00.248Z",
+ "__v": 0
+ },
+ {
+ "_id": "66863b14437936b46e225d79",
+ "monitorId": "66863aa2437936b46e225d1f",
+ "status": false,
+ "responseTime": 140,
+ "expiry": "2024-07-04T06:03:00.167Z",
+ "statusCode": 404,
+ "createdAt": "2024-07-04T06:03:00.168Z",
+ "updatedAt": "2024-07-04T06:03:00.168Z",
+ "__v": 0
+ }
+ ]
+ };
+
+ /**
+ * Function to calculate uptime duration based on the most recent check.
+ * @param {Array} checks Array of check objects.
+ * @returns {string} Uptime duration in hours, minutes, and seconds.
+ * TODO - NEED TO REVISIT THIS FOR PROPER LOGIC.
+ */
+ const calculateUptimeDuration = (checks) => {
+ if (!checks || checks.length === 0) {
+ return 'N/A';
+ }
+
+ const mostRecentCheck = checks[0];
+ const currentTime = new Date();
+ const lastCheckedTime = new Date(mostRecentCheck.createdAt);
+ let uptimeDuration = currentTime - lastCheckedTime;
+
+ // Calculate hours, minutes, and seconds from uptime duration
+ // TODO - NEED TO REVISIT THIS FOR PROPER LOGIC.
+ let uptimeHours = Math.floor(uptimeDuration / (1000 * 60 * 60));
+ uptimeDuration %= (1000 * 60 * 60);
+ let uptimeMinutes = Math.floor(uptimeDuration / (1000 * 60));
+ uptimeDuration %= (1000 * 60);
+ let uptimeSeconds = Math.floor(uptimeDuration / 1000);
+
+ return `${uptimeHours}h ${uptimeMinutes}m ${uptimeSeconds}s`;
+ };
+
+ /**
+ * Helper function to get timestamp of the most recent check.
+ * @param {Array} checks Array of check objects.
+ * @returns {string} Timestamp of the most recent check.
+ * TODO - NEED TO REVISIT THIS FOR PROPER LOGIC.
+ */
+ const getLastCheckedTimestamp = (checks) => {
+ if (!checks || checks.length === 0) {
+ return 'N/A'; // Handle case when no checks are available
+ }
+
+ const mostRecentCheck = checks[0];
+ return new Date(mostRecentCheck.createdAt).toLocaleString();
+ };
+
+ /**
+ * Helper function to count incidents (checks with status === false).
+ * @param {Array} checks Array of check objects.
+ * @returns {number} Number of incidents.
+ * TODO - NEED TO REVISIT THIS FOR PROPER LOGIC.
+ */
+ const countIncidents = (checks) => {
+ if (!checks || checks.length === 0) {
+ return 0; // Handle case when no checks are available
+ }
+
+ // Count checks with status === false
+ // TODO - NEED TO REVISIT THIS FOR PROPER LOGIC.
+ const incidentCount = checks.filter(check => !check.status).length;
+ return incidentCount;
+ };
+
+ return (
+
+ {/* Customized Tables Component */}
+
+
+ {/* Uptime duration */}
+
+ Up for: {calculateUptimeDuration(monitorData.checks)}
+
+
+ {/* Last checked */}
+
+ Last checked: {getLastCheckedTimestamp(monitorData.checks)}
+
+
+ {/* Incidents */}
+
+ Incidents: {countIncidents(monitorData.checks)}
+
+
+ );
+};
+
+export default DetailsPage;