Enhance admin dashboard analytics and system status
Added 'Year to Date' and 'Last Year' filters to analytics, and improved summary cards to show total revenue and orders for the selected period. Refactored SystemStatusCard to include a debug view with detailed system metrics and raw JSON response. Updated nav-item active state detection for more precision and improved navigation handling. Removed redundant recent activity card from admin status page.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
import { fetchClient } from "@/lib/api-client";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
|
||||
interface Status {
|
||||
uptimeSeconds: number;
|
||||
@@ -16,9 +18,18 @@ function formatDuration(seconds: number) {
|
||||
return `${h}h ${m}m ${s}s`;
|
||||
}
|
||||
|
||||
function formatBytes(bytes: number): string {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
export default function SystemStatusCard() {
|
||||
const [data, setData] = useState<Status | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [showDebug, setShowDebug] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
@@ -35,36 +46,103 @@ export default function SystemStatusCard() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-border/60 bg-background p-4 h-full min-h-[200px]">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<h2 className="font-medium">System status</h2>
|
||||
<p className="text-sm text-muted-foreground mt-1">Uptime, versions, environment</p>
|
||||
<div className="space-y-4">
|
||||
<div className="rounded-lg border border-border/60 bg-background p-4 h-full min-h-[200px]">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<h2 className="font-medium">System status</h2>
|
||||
<p className="text-sm text-muted-foreground mt-1">Uptime, versions, environment</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs px-2 py-0.5 rounded bg-emerald-500/15 text-emerald-400">OK</span>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setShowDebug(!showDebug)}
|
||||
>
|
||||
{showDebug ? 'Hide' : 'Show'} Debug
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-xs px-2 py-0.5 rounded bg-emerald-500/15 text-emerald-400">OK</span>
|
||||
|
||||
{error && <p className="text-sm text-muted-foreground mt-3">{error}</p>}
|
||||
|
||||
{data && (
|
||||
<div className="mt-3 grid grid-cols-2 gap-3 text-sm">
|
||||
<div className="space-y-1">
|
||||
<div className="text-muted-foreground">Uptime</div>
|
||||
<div>{formatDuration(data.uptimeSeconds)}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-muted-foreground">Node</div>
|
||||
<div>{data.versions?.node}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-muted-foreground">Vendors</div>
|
||||
<div>{data.counts?.vendors}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-muted-foreground">Orders</div>
|
||||
<div>{data.counts?.orders}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{error && <p className="text-sm text-muted-foreground mt-3">{error}</p>}
|
||||
|
||||
{data && (
|
||||
<div className="mt-3 grid grid-cols-2 gap-3 text-sm">
|
||||
<div className="space-y-1">
|
||||
<div className="text-muted-foreground">Uptime</div>
|
||||
<div>{formatDuration(data.uptimeSeconds)}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-muted-foreground">Node</div>
|
||||
<div>{data.versions?.node}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-muted-foreground">Vendors</div>
|
||||
<div>{data.counts?.vendors}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-muted-foreground">Orders</div>
|
||||
<div>{data.counts?.orders}</div>
|
||||
</div>
|
||||
</div>
|
||||
{showDebug && data && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Debug: Raw System Status Data</CardTitle>
|
||||
<CardDescription>Complete system status response from backend</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4 text-xs font-mono">
|
||||
<div>
|
||||
<div className="font-semibold mb-2">Memory Usage:</div>
|
||||
<div className="pl-4 space-y-1">
|
||||
<div>RSS (Resident Set Size): {formatBytes(data.memory?.rss || 0)}</div>
|
||||
<div>Heap Total: {formatBytes(data.memory?.heapTotal || 0)}</div>
|
||||
<div>Heap Used: {formatBytes(data.memory?.heapUsed || 0)}</div>
|
||||
<div>External: {formatBytes(data.memory?.external || 0)}</div>
|
||||
<div>Array Buffers: {formatBytes(data.memory?.arrayBuffers || 0)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="font-semibold mb-2">Versions:</div>
|
||||
<div className="pl-4 space-y-1">
|
||||
{Object.entries(data.versions || {}).map(([key, value]) => (
|
||||
<div key={key}>{key}: {value}</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="font-semibold mb-2">Counts:</div>
|
||||
<div className="pl-4 space-y-1">
|
||||
<div>Vendors: {data.counts?.vendors || 0}</div>
|
||||
<div>Orders: {data.counts?.orders || 0}</div>
|
||||
<div>Products: {data.counts?.products || 0}</div>
|
||||
<div>Chats: {data.counts?.chats || 0}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="font-semibold mb-2">Uptime:</div>
|
||||
<div className="pl-4">
|
||||
{data.uptimeSeconds} seconds ({formatDuration(data.uptimeSeconds)})
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<details className="mt-4">
|
||||
<summary className="font-semibold cursor-pointer">Full JSON Response</summary>
|
||||
<pre className="mt-2 bg-muted p-4 rounded overflow-auto max-h-96 text-[10px]">
|
||||
{JSON.stringify(data, null, 2)}
|
||||
</pre>
|
||||
</details>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user