diff --git a/src/App.css b/src/App.css index 36bb362..64c7b22 100644 --- a/src/App.css +++ b/src/App.css @@ -2,8 +2,6 @@ body { font-family: 'Poppins', sans-serif !important; transition: background-color 0.3s, color 0.3s; - padding-top: 70px; /* Sesuaikan dengan tinggi Navbar */ - padding-left: 250px; } body.light { @@ -16,31 +14,169 @@ body.dark { color: #ffffff; } +.theme-transition { + opacity: 0; + animation: fadeIn 0.5s ease-in-out forwards; +} + +@keyframes fadeIn { + from { + opacity: 0.2; + } + to { + opacity: 1; + } +} + +.theme-toggle-btn { + background-color: transparent; + border: none; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border-radius: 50%; + transition: background-color 0.3s, transform 0.2s ease-in-out; +} + +/* Light Mode */ +.light .theme-toggle-btn { + background-color: rgba(0, 0, 0, 0.1); + color: #1d1d1d; +} + +/* Dark Mode */ +.dark .theme-toggle-btn { + background-color: rgba(255, 255, 255, 0.1); + color: #ffffff; +} + +/* Hover Effect */ +.theme-toggle-btn:hover { + transform: scale(1.1); + opacity: 0.8; +} + +@media (max-width: 768px) { + .sidebar-app { + display: none; + } + + .main-content { + margin-left: 0; /* Pastikan kontennya full width */ + } +} + +/* Styling untuk tombol modal hanya tampil di bawah 768px */ +@media (min-width: 768px) { + .menu-toggle-btn, .sidebar-toggle-btn { + display: none; + } + + .main-content { + margin-top: 75px; + margin-left: 250px; /* Pastikan kontennya full width */ + } +} + +/* Styling modal */ +/* Styling untuk tombol modal hanya tampil di bawah 768px */ +@media (min-width: 768px) { + .menu-toggle-btn, + .sidebar-toggle-btn { + display: none; + } +} + +/* Styling modal menyesuaikan dengan tema */ +.sidebar-modal .modal-content { + transition: background-color 0.3s, color 0.3s; + border-radius: 8px; +} + +.light .sidebar-modal .modal-content { + background-color: #ffffff; + color: #1d1d1d; +} + +.dark .sidebar-modal .modal-content { + background-color: #161616; + color: white; +} + +.sidebar-modal .modal-header { + border-bottom: 1px solid #444; +} + +.light .sidebar-modal .modal-header { + border-bottom: 1px solid #ddd; +} + +.sidebar-modal .modal-title { + font-size: 1.5rem; +} + +.sidebar-modal .modal-body { + padding: 20px; +} + +.sidebar-modal .nav-link { + padding: 10px; + border-radius: 5px; + text-decoration: none; + transition: background-color 0.3s; +} + +.light .sidebar-modal .nav-link { + color: #1d1d1d; +} + +.dark .sidebar-modal .nav-link { + color: white; +} + +.light .sidebar-modal .nav-link:hover { + background-color: rgba(0, 0, 0, 0.1); +} + +.dark .sidebar-modal .nav-link:hover { + background-color: rgba(255, 255, 255, 0.1); +} + + .navbar-app { display: flex; justify-content: space-between; align-items: center; padding-top: 10px; padding-bottom: 10px; + transition: background-color 0.3s, color 0.3s, box-shadow 0.3s; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* Default shadow */ } -.light.navbar-app { +/* Light Mode Navbar */ +.light .navbar-app { background-color: #ffffff; - transition: background-color 0.3s, color 0.3s; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* Soft shadow */ } -.light.navbar-brand { +.light .navbar-brand { color: #161616; - transition: background-color 0.3s, color 0.3s; } -.dark.navbar-app { +/* Dark Mode Navbar */ +.dark .navbar-app { background-color: #161616; - transition: background-color 0.3s, color 0.3s; + box-shadow: 0 4px 12px rgba(255, 255, 255, 0.1); /* Lebih jelas di dark mode */ } -.dark.navbar-brand { - transition: background-color 0.3s, color 0.3s; +.dark .navbar-app:hover { + box-shadow: 0 6px 18px rgba(255, 255, 255, 0.2); /* Efek hover agar terlihat lebih elegan */ +} + +.dark .navbar-brand { color: #ffffff; } @@ -70,13 +206,30 @@ button:hover { /* border-right: 1px solid #414141; */ } +.sidebar-app.closed { + transform: translateX(-100%); +} + +.sidebar-toggle-btn { + background: none; + border: none; + cursor: pointer; + color: inherit; +} + +.sidebar-dropdown-toggle { + background-color: transparent; + border: none; + color: inherit; + cursor: pointer; +} + /* Styling Default Link */ .sidebar-app .nav-link { margin: 5px 15px; font-size: 16px; padding: 12px 15px; border-radius: 5px; - transition: background 0.3s, color 0.3s; text-decoration: none; /* Hilangkan underline */ } @@ -91,3 +244,380 @@ button:hover { color: white !important; font-weight: bold; } + +/* LIGHT MODE - Sidebar */ +.light .sidebar-app { + background-color: #f8f9fa; + color: #1d1d1d; + border-right: 1px solid #ddd; +} + +/* DARK MODE - Sidebar */ +.dark .sidebar-app { + background-color: #161616; + color: #ffffff; + border-right: 1px solid #444; +} + +/* LIGHT MODE - Sidebar Link */ +.light .nav-link { + color: #1d1d1d; + background-color: transparent; +} + +/* DARK MODE - Sidebar Link */ +.dark .nav-link { + color: #ffffff; + background-color: transparent; +} + +/* Hover Effect */ +.light .nav-link:hover { + background-color: rgba(0, 0, 0, 0.1); +} + +.dark .nav-link:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +/* Aktif Link */ +.light .nav-link.active { + background-color:#d32f2f; + color:rgb(255, 255, 255) !important; + font-weight: bold; +} + +.dark .nav-link.active { + background-color:#EF5350; + color: white !important; + font-weight: bold; +} + +/* ======================= */ +/* CARD STYLING - START */ +/* ======================= */ + +.card { + border-radius: 12px; + transition: background-color 0.3s, color 0.3s; +} + +@media (max-width: 768px) { + .card { + width: 100%; + margin-bottom: 10px; + } +} + +.light .card { + background-color: #ffffff; + color: #1d1d1d; + border: 1px solid #ddd; +} + +.light .card-header { + background-color: #f8f9fa; + color: #1d1d1d; + font-weight: bold; + border-bottom: 1px solid #ddd; +} + +.dark .card { + background-color: #252525; + color: #ffffff; + border: 1px solid #444; +} + +.dark .card-header { + background-color: #333333; + color: #ffffff; + font-weight: bold; + border-bottom: 1px solid #444; +} + +/* Styling untuk Card Header */ +.card-header { + font-size: 1rem; + font-weight: bold; + text-align: left; + padding: 12px 16px; + border-bottom: none; +} + +/* Styling untuk Card Body */ +.card-body { + padding: 20px; +} + +/* Styling untuk Card Title */ +.card-title { + font-size: 1.5rem; + font-weight: bold; + margin-top: 10px; +} + +/* Hover Effect */ +.card:hover { + transform: scale(1.03); + transition: transform 0.2s ease-in-out; +} + +/* ======================= */ +/* CARD STYLING - END */ +/* ======================= */ + +/* ======================= */ +/* METRICS GRID TABLE */ +/* ======================= */ + +.metrics-container { + display: flex; + flex-direction: column; + border-radius: 8px; + overflow: hidden; + margin-bottom: 20px; + transition: background-color 0.3s, color 0.3s; +} + +.metrics-header, .metrics-row { + display: grid; + grid-template-columns: 1fr 2fr 1fr 1fr 1fr 1fr; + gap: 10px; + padding: 12px; + text-align: center; +} + +/* Header Styling */ +.metrics-header { + font-weight: bold; +} + +/* LIGHT MODE */ +.light .metrics-container { + background-color: #ffffff; + color: #1d1d1d; + border: 1px solid #ddd; +} + +.light .metrics-header { + background-color: #f5f5f5; + color: #000; +} + +.light .metrics-body .metrics-row { + background-color: #ffffff; + color: #1d1d1d; +} + +.light .metrics-body .metrics-row:nth-child(even) { + background-color: #eeeeee; +} + +/* DARK MODE */ +.dark .metrics-container { + background-color: #161616; + color: #ffffff; + border: 1px solid #444; +} + +.dark .metrics-header { + background-color: #333333; + color: #ffffff; +} + +.dark .metrics-body .metrics-row { + background-color: #222222; + color: #ffffff; +} + +.dark .metrics-body .metrics-row:nth-child(even) { + background-color: #2a2a2a; +} + +/* Link Styling */ +.metrics-row a { + color: #4CAF50; + text-decoration: none; +} + +.metrics-row a:hover { + text-decoration: underline; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .metrics-header, .metrics-row { + grid-template-columns: 1fr 1fr 1fr; /* Kurangi jumlah kolom agar lebih rapi di mobile */ + font-size: 14px; + } +} + +/* ======================= */ +/* DATA TABLE GRID STYLING */ +/* ======================= */ + +.data-table-container { + display: flex; + flex-direction: column; + border-radius: 8px; + overflow: hidden; + margin-bottom: 20px; + transition: background-color 0.3s, color 0.3s; +} + +.data-table-header, .data-table-row { + display: grid; + grid-template-columns: 1fr 2fr 2fr 2fr 2fr 2fr 3fr 3fr; + gap: 10px; + padding: 12px; + text-align: center; + align-items: center; +} + +/* HEADER */ +.data-table-header { + font-weight: bold; +} + +/* LIGHT MODE */ +.light .data-table-container { + background-color: #ffffff; + color: #1d1d1d; + border: 1px solid #ddd; +} + +.light .data-table-header { + background-color: #f5f5f5; + color: #000; +} + +.light .data-table-body .data-table-row { + background-color: #ffffff; + color: #1d1d1d; +} + +.light .data-table-body .data-table-row:nth-child(even) { + background-color: #eeeeee; +} + +/* DARK MODE */ +.dark .data-table-container { + background-color: #161616; + color: #ffffff; + border: 1px solid #444; +} + +.dark .data-table-header { + background-color: #333333; + color: #ffffff; +} + +.dark .data-table-body .data-table-row { + background-color: #222222; + color: #ffffff; +} + +.dark .data-table-body .data-table-row:nth-child(even) { + background-color: #2a2a2a; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .data-table-header, .data-table-row { + grid-template-columns: 1fr 1fr 1fr 1fr; /* Kurangi jumlah kolom di mobile */ + font-size: 14px; + } +} + +/* ======================= */ +/* DEVICE TABLE GRID STYLE */ +/* ======================= */ + +.device-table-container { + display: flex; + flex-direction: column; + border-radius: 8px; + overflow: hidden; + margin-bottom: 20px; + transition: background-color 0.3s, color 0.3s; +} + +.device-table-header, .device-table-row { + display: grid; + grid-template-columns: 3fr 3fr 2fr; + gap: 10px; + padding: 12px; + text-align: center; + align-items: center; +} + +/* HEADER */ +.device-table-header { + font-weight: bold; +} + +/* LIGHT MODE */ +.light .device-table-container { + background-color: #ffffff; + color: #1d1d1d; + border: 1px solid #ddd; +} + +.light .device-table-header { + background-color: #f5f5f5; + color: #000; +} + +.light .device-table-body .device-table-row { + background-color: #ffffff; + color: #1d1d1d; +} + +.light .device-table-body .device-table-row:nth-child(even) { + background-color: #eeeeee; +} + +/* DARK MODE */ +.dark .device-table-container { + background-color: #161616; + color: #ffffff; + border: 1px solid #444; +} + +.dark .device-table-header { + background-color: #333333; + color: #ffffff; +} + +.dark .device-table-body .device-table-row { + background-color: #222222; + color: #ffffff; +} + +.dark .device-table-body .device-table-row:nth-child(even) { + background-color: #2a2a2a; +} + +/* Status Styling */ +.status { + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; +} + +.online { + color: green; +} + +.offline { + color: red; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .device-table-header, .device-table-row { + grid-template-columns: 1fr 1fr; + font-size: 14px; + } +} \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 36f9971..248c63f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,7 +1,7 @@ import "bootstrap/dist/css/bootstrap.min.css" import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import Sidebar from './components/layout/Sidebar'; -import Navbar from './components/layout/Navbar'; +import AppNavbar from './components/layout/Navbar'; import Dashboard from './pages/Dashboard'; import DevicesPage from './pages/DevicesPage'; import ReportPage from "./pages/ReportPage"; @@ -10,8 +10,8 @@ import { useEffect, useState } from "react"; import './App.css'; function App() { - const [theme, setTheme] = useState(localStorage.getItem("theme") || "light"); + const [isSidebarOpen, setIsSidebarOpen] = useState(false); useEffect(() => { document.body.className = theme; @@ -22,18 +22,22 @@ function App() { setTheme(prevTheme => (prevTheme === "light" ? "dark" : "light")); }; + const toggleSidebar = () => { + setIsSidebarOpen(!isSidebarOpen); + }; + return ( -
- - +
+ +
- }/> - }/> - }/> - }/> - }/> + } /> + }/> + } /> + } /> + } />
diff --git a/src/components/charts/DownloadChart.jsx b/src/components/charts/DownloadChart.jsx index ffc5bdf..1e248e3 100644 --- a/src/components/charts/DownloadChart.jsx +++ b/src/components/charts/DownloadChart.jsx @@ -1,6 +1,9 @@ import ReactApexChart from 'react-apexcharts'; -const DownloadChart = ({ data }) => { +const DownloadChart = ({ data, theme }) => { + + const isDark = theme === 'dark'; + const chartData = { series: [ { @@ -15,39 +18,39 @@ const DownloadChart = ({ data }) => { chart: { height: 250, type: 'area', - background: '#1e1e1e', + background: isDark ? '#1e1e1e' : '#ffffff', toolbar: { show: false }, }, dataLabels: { enabled: false }, stroke: { curve: 'smooth', - colors: ['#4CAF50'], + colors: [isDark ? '#4CAF50' : '#28a745'], }, xaxis: { type: 'datetime', - labels: { style: { fontFamily: 'Poppins, sans-serif', colors: '#ffffff' } }, - axisBorder: { color: '#777777' }, - axisTicks: { color: '#777777' }, + labels: { style: { fontFamily: 'Poppins, sans-serif', colors: isDark ? '#ffffff' : '#333333'} }, + axisBorder: { color: isDark ? '#777777' : '#cccccc' }, + axisTicks: { color: isDark ? '#777777' : '#cccccc' }, }, yaxis: { - labels: { style: { fontFamily: 'Poppins, sans-serif', colors: '#ffffff' } }, + labels: { style: { fontFamily: 'Poppins, sans-serif', colors: isDark ? '#ffffff' : '#333333' } }, }, grid: { borderColor: '#777777', strokeDashArray: 4, }, tooltip: { - theme: 'dark', + theme: isDark ? 'dark' : 'light', x: { format: 'dd/MM/yy HH:mm' }, y: { formatter: (val) => `${val} Mbps` }, }, - colors: ['#4CAF50'], + colors: [ isDark ? '#4CAF50' : '#28a745'], fill: { type: 'gradient', gradient: { - shade: 'dark', + shade: isDark ? 'dark' : 'light', type: 'vertical', - gradientToColors: ['#28a745'], + gradientToColors: [ isDark ? '#28a745' : '#4CAF50'], stops: [0, 100], }, }, diff --git a/src/components/charts/PingChart.jsx b/src/components/charts/PingChart.jsx index 2b061b0..1d5b3d1 100644 --- a/src/components/charts/PingChart.jsx +++ b/src/components/charts/PingChart.jsx @@ -1,7 +1,10 @@ /* eslint-disable react/prop-types */ import ReactApexChart from 'react-apexcharts'; -const PingChart = ({ data }) => { +const PingChart = ({ data, theme }) => { + + const isDark = theme === 'dark'; + const chartData = { series: [ { @@ -16,39 +19,39 @@ const PingChart = ({ data }) => { chart: { height: 250, type: 'area', - background: '#1e1e1e', + background: isDark ? '#1e1e1e' : '#ffffff', toolbar: { show: false }, }, dataLabels: { enabled: false }, stroke: { curve: 'smooth', - colors: ['#ffc107'], + colors: [ isDark ? '#ffc107' : '#d4a307'], }, xaxis: { type: 'datetime', - labels: { style: { fontFamily: 'Poppins, sans-serif', colors: '#ffffff' } }, - axisBorder: { color: '#777777' }, - axisTicks: { color: '#777777' }, + labels: { style: { fontFamily: 'Poppins, sans-serif', colors: isDark ? '#ffffff' : '#333333' } }, + axisBorder: { color: isDark ? '#777777' : '#cccccc' }, + axisTicks: { color: isDark ? '#777777' : '#cccccc' }, }, yaxis: { - labels: { style: { fontFamily: 'Poppins, sans-serif', colors: '#ffffff' } }, + labels: { style: { fontFamily: 'Poppins, sans-serif', colors: isDark ? '#ffffff' : '#333333' } }, }, grid: { - borderColor: '#777777', + borderColor: isDark ? '#777777' : '#cccccc', strokeDashArray: 4, }, tooltip: { - theme: 'dark', + theme: isDark ? 'dark' : 'light', x: { format: 'dd/MM/yy HH:mm' }, y: { formatter: (val) => `${val} Mbps` }, }, - colors: ['#ffc107'], + colors: [ isDark ? '#ffc107' : '#d4a307'], fill: { type: 'gradient', gradient: { - shade: 'dark', + shade: isDark ? 'dark' : 'light', type: 'vertical', - gradientToColors: ['#ffc107'], + gradientToColors: [ isDark ? '#ffc107' : '#d4a307'], stops: [0, 100], }, }, diff --git a/src/components/charts/UploadChart.jsx b/src/components/charts/UploadChart.jsx index dd889a7..e29fd31 100644 --- a/src/components/charts/UploadChart.jsx +++ b/src/components/charts/UploadChart.jsx @@ -1,6 +1,9 @@ import ReactApexChart from 'react-apexcharts'; -const UploadChart = ({ data }) => { +const UploadChart = ({ data, theme }) => { + + const isDark = theme === 'dark'; + const chartData = { series: [ { @@ -15,39 +18,39 @@ const UploadChart = ({ data }) => { chart: { height: 250, type: 'area', - background: '#1e1e1e', + background: isDark ? '#1e1e1e' : '#ffffff', toolbar: { show: false }, }, dataLabels: { enabled: false }, stroke: { curve: 'smooth', - colors: ['#00bcd4'], + colors: [ isDark ? '#00bcd4' : '#0097a7'], }, xaxis: { type: 'datetime', - labels: { style: { fontFamily: 'Poppins, sans-serif', colors: '#ffffff' } }, - axisBorder: { color: '#777777' }, - axisTicks: { color: '#777777' }, + labels: { style: { fontFamily: 'Poppins, sans-serif', colors: isDark ? '#ffffff' : '#333333' } }, + axisBorder: { color: isDark ? '#777777' : '#cccccc' }, + axisTicks: { color: isDark ? '#777777' : '#cccccc' }, }, yaxis: { - labels: { style: { fontFamily: 'Poppins, sans-serif', colors: '#ffffff' } }, + labels: { style: { fontFamily: 'Poppins, sans-serif', colors: isDark ? '#ffffff' : '#333333' } }, }, grid: { - borderColor: '#777777', + borderColor: isDark ? '#777777' : '#cccccc', strokeDashArray: 4, }, tooltip: { - theme: 'dark', + theme: isDark ? 'dark' : 'light', x: { format: 'dd/MM/yy HH:mm' }, y: { formatter: (val) => `${val} Mbps` }, }, - colors: ['#00bcd4'], + colors: [ isDark ? '#00bcd4' : '#0097a7'], fill: { type: 'gradient', gradient: { - shade: 'dark', + shade: isDark ? 'dark' : 'light', type: 'vertical', - gradientToColors: ['#007bff'], + gradientToColors: [ isDark ? '#0097a7' : '#00bcd4'], stops: [0, 100], }, }, diff --git a/src/components/dashboard/AppDevice.jsx b/src/components/dashboard/AppDevice.jsx index 7c77108..4658261 100644 --- a/src/components/dashboard/AppDevice.jsx +++ b/src/components/dashboard/AppDevice.jsx @@ -1,41 +1,43 @@ /* eslint-disable react/prop-types */ -import { Table } from 'react-bootstrap'; import { FaCheckCircle, FaTimesCircle } from "react-icons/fa"; -const AppDevice = ({ devices }) => { +const AppDevice = ({ devices, theme }) => { return ( - <> - - - - - - - - - - {devices.map((device) => ( - - - - - - ))} - -
IP AddressDevice NameStatus
{device.ip}{device.name} - {device.is_online === "Online" ? ( - <> - - Online - - ) : ( - <> - - Offline - - )} -
- +
+ {/* Header */} +
+
IP Address
+
Device Name
+
Status
+
+ + {/* Body */} +
+ {devices.map((device) => ( +
+
{device.ip}
+
{device.name}
+
+ {device.is_online === "Online" ? ( + <> + + Online + + ) : ( + <> + + Offline + + )} +
+
+ ))} +
+
); }; diff --git a/src/components/dashboard/AverageData.jsx b/src/components/dashboard/AverageData.jsx index 00a6326..17c26ee 100644 --- a/src/components/dashboard/AverageData.jsx +++ b/src/components/dashboard/AverageData.jsx @@ -2,7 +2,7 @@ import { Card, Col, Row } from 'react-bootstrap'; import { FaDownload, FaUpload, FaTachometerAlt } from 'react-icons/fa'; -const AverageData = ({ data }) => { +const AverageData = ({ data, theme }) => { const average = { download: 0, upload: 0, @@ -24,7 +24,7 @@ const AverageData = ({ data }) => { return ( - + Average Download @@ -35,7 +35,7 @@ const AverageData = ({ data }) => { - + Average Upload @@ -46,7 +46,7 @@ const AverageData = ({ data }) => { - + Average Ping diff --git a/src/components/dashboard/ChartData.jsx b/src/components/dashboard/ChartData.jsx index ea0b9ea..311aeec 100644 --- a/src/components/dashboard/ChartData.jsx +++ b/src/components/dashboard/ChartData.jsx @@ -10,35 +10,35 @@ const Chart = ({ data, theme }) => { <> - + Download - + - + Upload - + - + Ping - + diff --git a/src/components/dashboard/MetricsTable.jsx b/src/components/dashboard/MetricsTable.jsx index a254fa8..1ff7526 100644 --- a/src/components/dashboard/MetricsTable.jsx +++ b/src/components/dashboard/MetricsTable.jsx @@ -1,36 +1,33 @@ -import Table from 'react-bootstrap/Table'; -const MetricsTable = ({ metrics = [] }) => { +const MetricsTable = ({ metrics = [], theme }) => { return ( -
- - - - - - - - - - - - - {metrics.map((item, index) => ( - - - - - - - - - ))} - -
Monitor NameURLResponse Time (ms)StatusCertificate ValidCert Days Remaining
{item.monitor_name}{item.monitor_url}{item.response_time} ms - {item.status === 1 ? 'UP' : - item.status === 0 ? 'DOWN' : - item.status === 2 ? 'PENDING' : 'MAINTENANCE'} - {item.cert_valid === 1 ? 'Yes' : 'No'}{item.cert_days_remaining}
+
+
+
Monitor Name
+
URL
+
Response Time (ms)
+
Status
+
Certificate Valid
+
Cert Days Remaining
+
+
+ {metrics.map((item, index) => ( +
+
{item.monitor_name}
+ +
{item.response_time} ms
+
+ {item.status === 1 ? "UP" : item.status === 0 ? "DOWN" : item.status === 2 ? "PENDING" : "MAINTENANCE"} +
+
{item.cert_valid === 1 ? "Yes" : "No"}
+
{item.cert_days_remaining}
+
+ ))} +
); }; diff --git a/src/components/dashboard/TableData.jsx b/src/components/dashboard/TableData.jsx index 107d0d8..e097255 100644 --- a/src/components/dashboard/TableData.jsx +++ b/src/components/dashboard/TableData.jsx @@ -1,50 +1,60 @@ -/* eslint-disable react/prop-types */ -import { Table } from 'react-bootstrap'; -import { format } from 'date-fns'; +import { format } from "date-fns"; import { FaDownload, FaUpload, FaTachometerAlt } from "react-icons/fa"; const DataTable = ({ data = [], theme }) => { return ( -
- - - - - - - - - - - - - - +
+ {/* Header */} +
+
No
+
+ Bytes +
+
+ Elapsed +
+
+ Bytes +
+
+ Elapsed +
+
+ Jitter +
+
Time
+
Server
+
+ + {/* Body */} +
{data.map((item, index) => ( -
- - - - - - - - - +
+
{index + 1}
+
+ {(item.data.download.bytes / 1048576).toFixed(1)} Mbps +
+
+ {(item.data.download.elapsed / 1000).toFixed(2)}s +
+
+ {(item.data.upload.bytes / 1048576).toFixed(1)} Mbps +
+
+ {(item.data.upload.elapsed / 1000).toFixed(2)}s +
+
{item.data.ping.jitter.toFixed(1)}ms
+
+ {format(new Date(item.datetime), "eeee, d MMMM yyyy HH:mm:ss")} +
+
+ {item.data.isp} ({item.data.server.name},{" "} + {item.data.server.location}) +
+
))} - -
No - Bytes - - Elapsed - - Bytes - - Elapsed - - Jitter - TimeServer
{index + 1}{(item.data.download.bytes / 1048576).toFixed(1)} Mbps{(item.data.download.elapsed / 1000).toFixed(2)}s{(item.data.upload.bytes / 1048576).toFixed(1)} Mbps{(item.data.upload.elapsed / 1000).toFixed(2)}s{(item.data.ping.jitter).toFixed(1)}ms{format(new Date(item.datetime), 'eeee, d MMMM yyyy HH:mm:ss')}{item.data.isp} ({item.data.server.name}, {item.data.server.location})
-
+
+
); }; diff --git a/src/components/layout/Navbar.jsx b/src/components/layout/Navbar.jsx index dad161c..b80d5e9 100644 --- a/src/components/layout/Navbar.jsx +++ b/src/components/layout/Navbar.jsx @@ -1,22 +1,52 @@ -import { Navbar, Nav } from 'react-bootstrap'; -import { FaChartLine, FaSun, FaMoon } from 'react-icons/fa'; +import { Navbar, Nav, Modal, Button } from 'react-bootstrap'; +import { FaChartLine, FaSun, FaMoon, FaBars } from 'react-icons/fa'; +import { useState } from 'react'; +import { Link } from 'react-router-dom'; const AppNavbar = ({ toggleTheme, theme }) => { + const [showModal, setShowModal] = useState(false); + return ( - - - - Speedtest Tracker - - - + <> + +
+ + Speedtest + +
+ +
+ + {/* Modal Sidebar */} + setShowModal(false)} centered> + + Menu + + + + + + ); }; diff --git a/src/components/layout/Sidebar.jsx b/src/components/layout/Sidebar.jsx index e981ef1..dc7a00c 100644 --- a/src/components/layout/Sidebar.jsx +++ b/src/components/layout/Sidebar.jsx @@ -1,48 +1,29 @@ import { Navbar, Nav } from 'react-bootstrap'; import { Link, useLocation } from 'react-router-dom'; -import { FaTachometerAlt, FaDesktop, FaChartBar, FaCog } from "react-icons/fa"; - -const Sidebar = ({theme}) => { +import { FaTachometerAlt, FaDesktop, FaChartBar, FaCog, FaBars } from "react-icons/fa"; +import { useState, useEffect } from 'react'; +const Sidebar = ({ theme }) => { const location = useLocation(); - + return ( - - - +
+ +
); -} +}; export default Sidebar; diff --git a/src/pages/Dashboard.jsx b/src/pages/Dashboard.jsx index eeeb6f1..cf1d011 100644 --- a/src/pages/Dashboard.jsx +++ b/src/pages/Dashboard.jsx @@ -1,11 +1,11 @@ import { useEffect, useState } from 'react'; import { Container, Spinner, Alert, Row, Col } from 'react-bootstrap'; -import { fetchSpeedTestData, fetchMetricsData } from '../services/api'; +import { fetchSpeedTestData } from '../services/api'; import AverageData from '../components/dashboard/AverageData'; import Chart from '../components/dashboard/ChartData'; import DataTable from '../components/dashboard/TableData'; -const Dashboard = () => { +const Dashboard = ({theme}) => { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -42,18 +42,18 @@ const Dashboard = () => { } return ( - +

Dashboard

- - + + - + diff --git a/src/pages/DevicesPage.jsx b/src/pages/DevicesPage.jsx index 938478a..e9f67a5 100644 --- a/src/pages/DevicesPage.jsx +++ b/src/pages/DevicesPage.jsx @@ -6,7 +6,7 @@ import MetricsTable from '../components/dashboard/MetricsTable'; import AppDevice from '../components/dashboard/AppDevice'; -function DevicesPage() { +function DevicesPage({theme}) { const [metrics, setMetrics] = useState([]); const [devices, setDevices] = useState([]); @@ -36,7 +36,7 @@ function DevicesPage() { if (loading) { return ( - + ); } @@ -50,11 +50,11 @@ function DevicesPage() { } return ( - +

Devices Page

- - + +
);