"use client"; import { useEffect, useState, useRef, useCallback } from "react"; import { getStats, type Stats, type NetworkInterface } from "./lib/getStats"; import SideNav from "./components/SideNav"; import Hero from "./components/Hero"; import StatsGrid from "./components/StatsGrid"; import ServicesCard from "./components/ServicesCard"; import UptimeCard from "./components/UptimeCard"; import NetworkCard from "./components/NetworkCard"; import PowerGrid from "./components/PowerGrid"; import LinksGrid from "./components/LinksGrid"; import DevConsole, { type LogEntry } from "./components/DevConsole"; import { useCheckAuth } from "@/hooks/useCheckAuth"; import { useRouter } from "next/navigation"; import { getPower, type PowerData } from "./lib/getPower"; export default function Home() { const router = useRouter(); useCheckAuth(); const [stats, setStats] = useState(null); const [power, setPower] = useState(null); const [netSpeed, setNetSpeed] = useState< Record >({}); const [panelOpen, setPanelOpen] = useState(false); const [panelWidth, setPanelWidth] = useState(440); const [isMobile, setIsMobile] = useState(false); const [logs, setLogs] = useState([]); const prevNetRef = useRef | null>(null); const lastFetchRef = useRef(0); const logIdRef = useRef(0); useEffect(() => { const check = () => setIsMobile(window.innerWidth < 768); check(); window.addEventListener("resize", check); return () => window.removeEventListener("resize", check); }, []); useEffect(() => { const original = window.fetch; window.fetch = async (input, init) => { const url = typeof input === "string" ? input : input instanceof URL ? input.href : (input as Request).url; const shouldLog = (url.startsWith("/api/") && !url.startsWith("/api/dev/proxy")) || url.includes("localhost:3001"); if (!shouldLog) return original(input, init); const method = ((init?.method ?? (input instanceof Request ? input.method : "GET")) as string).toUpperCase(); const id = ++logIdRef.current; let path = url; try { path = new URL(url, window.location.origin).pathname; } catch { // use raw url } const timestamp = new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }); const start = Date.now(); setLogs((prev) => [ ...prev, { id, method, path, url, status: null, duration: null, timestamp, response: null }, ]); try { const res = await original(input, init); const clone = res.clone(); const text = await clone.text(); const duration = Date.now() - start; setLogs((prev) => prev.map((e) => (e.id === id ? { ...e, status: res.status, duration, response: text } : e)) ); return res; } catch (err) { const duration = Date.now() - start; setLogs((prev) => prev.map((e) => (e.id === id ? { ...e, status: 0, duration, response: String(err) } : e)) ); throw err; } }; return () => { window.fetch = original; }; }, []); useEffect(() => { const fetchData = async () => { try { const now = Date.now(); const data = await getStats(); if (prevNetRef.current && lastFetchRef.current > 0) { const elapsed = (now - lastFetchRef.current) / 1000; const speeds: Record = {}; for (const iface of Object.keys(data.network)) { const prev = prevNetRef.current[iface]; if (prev) { speeds[iface] = { rx: Math.max(0, (data.network[iface].rx - prev.rx) / elapsed), tx: Math.max(0, (data.network[iface].tx - prev.tx) / elapsed), }; } } setNetSpeed(speeds); } prevNetRef.current = data.network; lastFetchRef.current = now; setStats(data); } catch (e) { if (e instanceof Error && e.message === "UNAUTHORIZED") { router.push( "/auth?callbackUrl=" + encodeURIComponent(window.location.pathname), ); return; } console.error("Dashboard fetch failed:", e); } }; fetchData(); const id = setInterval(fetchData, 4000); return () => clearInterval(id); }, []); const fetchPower = useCallback(async () => { try { setPower(await getPower()); } catch (e) { if (e instanceof Error && e.message === "UNAUTHORIZED") return; console.error("Power fetch failed:", e); } }, []); useEffect(() => { fetchPower(); const id = setInterval(fetchPower, 10000); return () => clearInterval(id); }, [fetchPower]); const primaryIface = stats ? Object.keys(stats.network).find( (k) => !k.startsWith("docker") && !k.startsWith("br-") && stats.network[k].rx > 0, ) : null; const primarySpeed = primaryIface ? netSpeed[primaryIface] || null : null; return (
setPanelOpen((o) => !o)} />

System Stats

Power Consumption

setPanelOpen(false)} onWidthChange={setPanelWidth} logs={logs} />
); }