refactor(web): split AdminDashboardView into admin-dashboard-view module
- types: DashboardStats, UploadItem, AuditLogItem, StatCardProps, Report
- useAdminDashboardView: fetchData, handleAction, triggerProtocol
- Header, StatCard, TrafficCard, ProtocolsCard, NodeHealthCard, Tabs
- AdminDashboardSkeleton for Loading state
- max-w-layout-content, text-xs, gap-0.5 (no arbitrary values)
- Stories: Default, Loading (Skeleton). Decorator min-h-layout-page
- Re-export from AdminDashboardView.tsx
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-06 16:54:02 +00:00
|
|
|
import React from 'react';
|
2026-02-07 15:46:36 +00:00
|
|
|
import { motion } from 'framer-motion';
|
refactor(web): split AdminDashboardView into admin-dashboard-view module
- types: DashboardStats, UploadItem, AuditLogItem, StatCardProps, Report
- useAdminDashboardView: fetchData, handleAction, triggerProtocol
- Header, StatCard, TrafficCard, ProtocolsCard, NodeHealthCard, Tabs
- AdminDashboardSkeleton for Loading state
- max-w-layout-content, text-xs, gap-0.5 (no arbitrary values)
- Stories: Default, Loading (Skeleton). Decorator min-h-layout-page
- Re-export from AdminDashboardView.tsx
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-06 16:54:02 +00:00
|
|
|
import { Users, DollarSign, Activity, ShieldAlert } from 'lucide-react';
|
|
|
|
|
import { useAdminDashboardView } from './useAdminDashboardView';
|
|
|
|
|
import { AdminDashboardHeader } from './AdminDashboardHeader';
|
|
|
|
|
import { AdminDashboardStatCard } from './AdminDashboardStatCard';
|
|
|
|
|
import { AdminDashboardTrafficCard } from './AdminDashboardTrafficCard';
|
|
|
|
|
import { AdminDashboardProtocolsCard } from './AdminDashboardProtocolsCard';
|
|
|
|
|
import { AdminDashboardNodeHealthCard } from './AdminDashboardNodeHealthCard';
|
|
|
|
|
import { AdminDashboardTabs } from './AdminDashboardTabs';
|
|
|
|
|
import { AdminDashboardSkeleton } from './AdminDashboardSkeleton';
|
|
|
|
|
import { Loader2 } from 'lucide-react';
|
|
|
|
|
|
|
|
|
|
export function AdminDashboardView() {
|
|
|
|
|
const {
|
|
|
|
|
stats,
|
|
|
|
|
reports,
|
|
|
|
|
uploads,
|
|
|
|
|
auditLogs,
|
|
|
|
|
loading,
|
|
|
|
|
protocolActive,
|
|
|
|
|
handleAction,
|
|
|
|
|
triggerProtocol,
|
|
|
|
|
} = useAdminDashboardView();
|
|
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex justify-center py-24">
|
|
|
|
|
<Loader2 className="w-10 h-10 text-primary animate-spin" />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-8 pb-24 animate-fadeIn container mx-auto px-4 py-8 max-w-layout-content">
|
|
|
|
|
<AdminDashboardHeader
|
|
|
|
|
protocolActive={protocolActive}
|
|
|
|
|
onRescan={() => triggerProtocol('RESCAN', 'success')}
|
|
|
|
|
onLockdown={() => triggerProtocol('LOCKDOWN', 'error')}
|
|
|
|
|
/>
|
|
|
|
|
|
2026-02-07 15:46:36 +00:00
|
|
|
<motion.div
|
2026-02-07 18:30:13 +00:00
|
|
|
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8"
|
2026-02-07 15:46:36 +00:00
|
|
|
initial="hidden"
|
|
|
|
|
animate="visible"
|
|
|
|
|
variants={{ visible: { transition: { staggerChildren: 0.05 } }, hidden: {} }}
|
|
|
|
|
>
|
|
|
|
|
{[
|
|
|
|
|
{ label: 'Total Nodes', value: stats.totalUsers?.toLocaleString(), icon: Users, trend: stats.trends?.users, color: 'cyan' as const },
|
|
|
|
|
{ label: 'Credit Volume', value: `$${stats.monthlyRevenue?.toLocaleString()}`, icon: DollarSign, trend: stats.trends?.revenue, color: 'gold' as const },
|
|
|
|
|
{ label: 'Active Uplinks', value: stats.activeSessions?.toLocaleString(), icon: Activity, trend: stats.trends?.sessions, color: 'lime' as const },
|
|
|
|
|
{ label: 'Threat Reports', value: stats.pendingReports, icon: ShieldAlert, trend: stats.trends?.reports, color: 'red' as const },
|
|
|
|
|
].map((item, i) => (
|
|
|
|
|
<motion.div key={item.label} variants={{ hidden: { opacity: 0, y: 8 }, visible: { opacity: 1, y: 0 } }}>
|
|
|
|
|
<AdminDashboardStatCard
|
|
|
|
|
label={item.label}
|
|
|
|
|
value={item.value}
|
|
|
|
|
icon={<item.icon className="w-5 h-5" />}
|
|
|
|
|
trend={item.trend}
|
|
|
|
|
color={item.color}
|
|
|
|
|
/>
|
|
|
|
|
</motion.div>
|
|
|
|
|
))}
|
|
|
|
|
</motion.div>
|
refactor(web): split AdminDashboardView into admin-dashboard-view module
- types: DashboardStats, UploadItem, AuditLogItem, StatCardProps, Report
- useAdminDashboardView: fetchData, handleAction, triggerProtocol
- Header, StatCard, TrafficCard, ProtocolsCard, NodeHealthCard, Tabs
- AdminDashboardSkeleton for Loading state
- max-w-layout-content, text-xs, gap-0.5 (no arbitrary values)
- Stories: Default, Loading (Skeleton). Decorator min-h-layout-page
- Re-export from AdminDashboardView.tsx
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-06 16:54:02 +00:00
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
|
|
|
<AdminDashboardTrafficCard />
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
<AdminDashboardProtocolsCard onTrigger={triggerProtocol} />
|
|
|
|
|
<AdminDashboardNodeHealthCard />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<AdminDashboardTabs
|
|
|
|
|
reports={reports}
|
|
|
|
|
uploads={uploads}
|
|
|
|
|
auditLogs={auditLogs}
|
|
|
|
|
onReportAction={handleAction}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|