From 3f8826cbc444208edc802ace6091afa307557ce9 Mon Sep 17 00:00:00 2001 From: g Date: Fri, 28 Nov 2025 19:22:14 +0000 Subject: [PATCH] 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. --- app/dashboard/admin/status/page.tsx | 36 +------ components/admin/AdminAnalytics.tsx | 33 ++++--- components/admin/SystemStatusCard.tsx | 132 ++++++++++++++++++++------ components/layout/nav-item.tsx | 17 +--- 4 files changed, 133 insertions(+), 85 deletions(-) diff --git a/app/dashboard/admin/status/page.tsx b/app/dashboard/admin/status/page.tsx index 618e143..b2d8570 100644 --- a/app/dashboard/admin/status/page.tsx +++ b/app/dashboard/admin/status/page.tsx @@ -3,6 +3,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com import { Badge } from "@/components/ui/badge"; import { Server, Database, Cpu, HardDrive, Activity } from "lucide-react"; import { fetchServer } from "@/lib/api"; +import SystemStatusCard from "@/components/admin/SystemStatusCard"; interface SystemStatus { uptimeSeconds: number; @@ -74,6 +75,8 @@ export default async function AdminStatusPage() {

Monitor system health and performance metrics

+ +
{/* Server Status */} @@ -172,39 +175,6 @@ export default async function AdminStatusPage() {
- - {/* Recent Activity */} - - - Recent System Activity - Latest system events and changes - - -
-
-
-
-

System health check completed

-

2 minutes ago

-
-
-
-
-
-

Database backup completed

-

1 hour ago

-
-
-
-
-
-

High memory usage detected

-

3 hours ago

-
-
-
-
-
); } diff --git a/components/admin/AdminAnalytics.tsx b/components/admin/AdminAnalytics.tsx index fd0d062..b5d5aa1 100644 --- a/components/admin/AdminAnalytics.tsx +++ b/components/admin/AdminAnalytics.tsx @@ -267,6 +267,8 @@ export default function AdminAnalytics() { Last 24 hours Last 7 days Last 30 days + Year to Date + Last Year @@ -534,20 +536,25 @@ export default function AdminAnalytics() { )} -
-
-
Total Orders
-
{analyticsData?.orders?.total?.toLocaleString() || '0'}
+ {/* Calculate totals for the selected period */} + {analyticsData?.orders?.dailyOrders && analyticsData?.revenue?.dailyRevenue && ( +
+
+
Total Revenue
+
+ {formatCurrency( + analyticsData.revenue.dailyRevenue.reduce((sum, day) => sum + (day.amount || 0), 0) + )} +
+
+
+
Total Orders
+
+ {analyticsData.orders.dailyOrders.reduce((sum, day) => sum + (day.count || 0), 0).toLocaleString()} +
+
-
-
Pending Orders
-
{analyticsData?.orders?.pending?.toLocaleString() || '0'}
-
-
-
Completed Orders
-
{analyticsData?.orders?.completed?.toLocaleString() || '0'}
-
-
+ )} diff --git a/components/admin/SystemStatusCard.tsx b/components/admin/SystemStatusCard.tsx index 55c7035..f0f428e 100644 --- a/components/admin/SystemStatusCard.tsx +++ b/components/admin/SystemStatusCard.tsx @@ -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(null); const [error, setError] = useState(null); + const [showDebug, setShowDebug] = useState(false); useEffect(() => { let mounted = true; @@ -35,36 +46,103 @@ export default function SystemStatusCard() { }, []); return ( -
-
-
-

System status

-

Uptime, versions, environment

+
+
+
+
+

System status

+

Uptime, versions, environment

+
+
+ OK + +
- OK + + {error &&

{error}

} + + {data && ( +
+
+
Uptime
+
{formatDuration(data.uptimeSeconds)}
+
+
+
Node
+
{data.versions?.node}
+
+
+
Vendors
+
{data.counts?.vendors}
+
+
+
Orders
+
{data.counts?.orders}
+
+
+ )}
- {error &&

{error}

} - - {data && ( -
-
-
Uptime
-
{formatDuration(data.uptimeSeconds)}
-
-
-
Node
-
{data.versions?.node}
-
-
-
Vendors
-
{data.counts?.vendors}
-
-
-
Orders
-
{data.counts?.orders}
-
-
+ {showDebug && data && ( + + + Debug: Raw System Status Data + Complete system status response from backend + + +
+
+
Memory Usage:
+
+
RSS (Resident Set Size): {formatBytes(data.memory?.rss || 0)}
+
Heap Total: {formatBytes(data.memory?.heapTotal || 0)}
+
Heap Used: {formatBytes(data.memory?.heapUsed || 0)}
+
External: {formatBytes(data.memory?.external || 0)}
+
Array Buffers: {formatBytes(data.memory?.arrayBuffers || 0)}
+
+
+ +
+
Versions:
+
+ {Object.entries(data.versions || {}).map(([key, value]) => ( +
{key}: {value}
+ ))} +
+
+ +
+
Counts:
+
+
Vendors: {data.counts?.vendors || 0}
+
Orders: {data.counts?.orders || 0}
+
Products: {data.counts?.products || 0}
+
Chats: {data.counts?.chats || 0}
+
+
+ +
+
Uptime:
+
+ {data.uptimeSeconds} seconds ({formatDuration(data.uptimeSeconds)}) +
+
+ +
+ Full JSON Response +
+                  {JSON.stringify(data, null, 2)}
+                
+
+
+
+
)}
); diff --git a/components/layout/nav-item.tsx b/components/layout/nav-item.tsx index b094b0e..efddf2a 100644 --- a/components/layout/nav-item.tsx +++ b/components/layout/nav-item.tsx @@ -16,7 +16,8 @@ interface NavItemProps { export const NavItem: React.FC = ({ href, icon: Icon, children, onClick }) => { const pathname = usePathname() - const isActive = pathname === href || (href !== '/dashboard' && pathname?.startsWith(href)) + // More precise active state detection - exact match or starts with href followed by / + const isActive = pathname === href || (href !== '/dashboard' && pathname?.startsWith(href + '/')) const isNavigatingRef = useRef(false) const handleClick = (e: React.MouseEvent) => { @@ -26,26 +27,18 @@ export const NavItem: React.FC = ({ href, icon: Icon, children, on return } - // If already on this page, just close mobile menu if needed - if (isActive) { - e.preventDefault() - if (onClick) onClick() - return - } - // Mark as navigating to prevent double-clicks isNavigatingRef.current = true - // Call onClick handler (for mobile menu closing) - don't block navigation + // Always allow navigation - close mobile menu if needed if (onClick) { - // Use setTimeout to ensure navigation happens first - setTimeout(() => onClick(), 0) + onClick() } // Reset flag after navigation completes setTimeout(() => { isNavigatingRef.current = false - }, 300) + }, 500) } return (