Sprint 1 — Quick A11y wins: - progress.tsx: role=progressbar + aria-value* + aria-label - switch.tsx: role=switch + aria-checked - skeleton.tsx: aria-hidden=true - alert.tsx, Toast.tsx, SelectTrigger.tsx: aria-labels on close buttons - PostCard.tsx: alt on images + aria-labels on icon buttons - ProductCard.tsx: aria-labels on play/view buttons - modal.tsx: role=dialog + aria-modal + aria-labelledby - input.tsx: error state + aria-invalid + aria-describedby - FAB.tsx: forward aria-label from label prop Sprint 2 — Structural A11y + View States: - tabs/: full ARIA tablist/tab/tabpanel + arrow key navigation - radio-group.tsx: role=radio + arrow key navigation - select/: aria-activedescendant + full keyboard navigation - List.tsx + card.tsx: focus-visible states on interactive elements - DashboardPage, LibraryPage, LiveView, QueueView: error states - WishlistView, AdminDashboard, AnalyticsView, SellerDashboard: loading/empty states Co-authored-by: Cursor <cursoragent@cursor.com>
94 lines
3.4 KiB
TypeScript
94 lines
3.4 KiB
TypeScript
import React from 'react';
|
|
import { motion } from 'framer-motion';
|
|
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 { ErrorDisplay } from '@/components/ui/ErrorDisplay';
|
|
|
|
export function AdminDashboardView() {
|
|
const {
|
|
stats,
|
|
reports,
|
|
uploads,
|
|
auditLogs,
|
|
loading,
|
|
error,
|
|
protocolActive,
|
|
handleAction,
|
|
triggerProtocol,
|
|
retry,
|
|
} = useAdminDashboardView();
|
|
|
|
if (loading) {
|
|
return <AdminDashboardSkeleton />;
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="container mx-auto px-4 py-8 max-w-layout-content">
|
|
<ErrorDisplay
|
|
error={error}
|
|
onRetry={retry}
|
|
title="Failed to load admin dashboard"
|
|
context={{ action: 'loading', resource: 'admin dashboard' }}
|
|
variant="card"
|
|
/>
|
|
</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')}
|
|
/>
|
|
|
|
<motion.div
|
|
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8"
|
|
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>
|
|
|
|
<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>
|
|
);
|
|
}
|