- Moved dashboard components (Donut, Gauge, Sparkline) to their own files for better organization. - Created a new DashboardHeader component to manage the header state and display service status. - Introduced a layout component for the dashboard to encapsulate common layout styles. - Simplified the Dashboard component by utilizing new components and reducing inline logic. - Added type definitions for dashboard data in a new types.ts file. - Enhanced the visual representation of data with improved SVG elements and accessibility attributes. - Removed redundant code and improved overall readability and maintainability.
82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import type { DashboardData } from "@/lib/dashboard/types";
|
|
|
|
export function DashboardHeader() {
|
|
const [degraded, setDegraded] = useState(0);
|
|
const [total, setTotal] = useState(0);
|
|
const [time, setTime] = useState("");
|
|
|
|
useEffect(() => {
|
|
const fetchStatus = async () => {
|
|
try {
|
|
const res = await fetch("/api/dashboard");
|
|
if (!res.ok) return;
|
|
const data: DashboardData = await res.json();
|
|
setTotal(data.services.length);
|
|
setDegraded(
|
|
data.services.length -
|
|
data.services.filter((s) => s.state === "running").length,
|
|
);
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
};
|
|
fetchStatus();
|
|
const id = setInterval(fetchStatus, 15000);
|
|
return () => clearInterval(id);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const tick = () =>
|
|
setTime(
|
|
new Date().toLocaleTimeString([], {
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
}),
|
|
);
|
|
tick();
|
|
const id = setInterval(tick, 10000);
|
|
return () => clearInterval(id);
|
|
}, []);
|
|
|
|
return (
|
|
<header className="sticky top-0 z-50 flex items-center justify-between gap-2 border-b bg-background/90 px-5 py-3 backdrop-blur-xl">
|
|
<a href="/" className="flex items-center gap-2.5">
|
|
<span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-foreground text-xs font-bold text-background">
|
|
AH
|
|
</span>
|
|
<h1 className="text-base font-semibold">Asep Haryana</h1>
|
|
</a>
|
|
<div className="flex items-center gap-2.5">
|
|
<Badge
|
|
variant="outline"
|
|
className={`h-auto gap-1.5 rounded-full px-3 py-1 text-xs font-medium ${
|
|
degraded > 0
|
|
? "border-amber-500/30 bg-amber-900/20 text-amber-500"
|
|
: total > 0
|
|
? "border-emerald-500/30 bg-emerald-900/20 text-emerald-400"
|
|
: ""
|
|
}`}
|
|
>
|
|
{total > 0 && (
|
|
<span
|
|
className={`h-1.5 w-1.5 rounded-full ${
|
|
degraded > 0 ? "bg-amber-500" : "bg-emerald-400"
|
|
}`}
|
|
/>
|
|
)}
|
|
{total === 0
|
|
? "No services"
|
|
: degraded > 0
|
|
? `${degraded} degraded`
|
|
: "All Systems Operational"}
|
|
</Badge>
|
|
<span className="text-[10px] text-muted-foreground">{time}</span>
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|