Enhance admin dashboard UI and tables with new styles
All checks were successful
Build Frontend / build (push) Successful in 1m4s

Refactors admin dashboard, users, vendors, shipping, and stock pages to improve UI consistency and visual clarity. Adds new icons, animated transitions, and card styles for stats and tables. Updates table row rendering with framer-motion for smooth animations, improves badge and button styling, and enhances search/filter inputs. Refines loading skeletons and overall layout for a more modern, accessible admin experience.
This commit is contained in:
g
2026-01-12 07:16:33 +00:00
parent 63c833b510
commit 73adbe5d07
6 changed files with 757 additions and 611 deletions

View File

@@ -37,7 +37,7 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error(`Error loading ${this.props.componentName || 'component'}:`, error, errorInfo);
// Log to error tracking service if available
if (typeof window !== 'undefined' && (window as any).gtag) {
(window as any).gtag('event', 'exception', {
@@ -105,31 +105,31 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
}
// Lazy load admin components with error handling
const AdminAnalytics = lazy(() =>
const AdminAnalytics = lazy(() =>
import("@/components/admin/AdminAnalytics").catch((err) => {
console.error("Failed to load AdminAnalytics:", err);
throw err;
})
);
const InviteVendorCard = lazy(() =>
const InviteVendorCard = lazy(() =>
import("@/components/admin/InviteVendorCard").catch((err) => {
console.error("Failed to load InviteVendorCard:", err);
throw err;
})
);
const BanUserCard = lazy(() =>
const BanUserCard = lazy(() =>
import("@/components/admin/BanUserCard").catch((err) => {
console.error("Failed to load BanUserCard:", err);
throw err;
})
);
const InvitationsListCard = lazy(() =>
const InvitationsListCard = lazy(() =>
import("@/components/admin/InvitationsListCard").catch((err) => {
console.error("Failed to load InvitationsListCard:", err);
throw err;
})
);
const VendorsCard = lazy(() =>
const VendorsCard = lazy(() =>
import("@/components/admin/VendorsCard").catch((err) => {
console.error("Failed to load VendorsCard:", err);
throw err;
@@ -139,7 +139,7 @@ const VendorsCard = lazy(() =>
// Loading skeleton with timeout warning
function AdminComponentSkeleton({ showSlowWarning = false }: { showSlowWarning?: boolean }) {
return (
<div
<div
className="space-y-6 animate-in fade-in duration-500 relative"
role="status"
aria-label="Loading analytics dashboard"
@@ -156,7 +156,7 @@ function AdminComponentSkeleton({ showSlowWarning = false }: { showSlowWarning?:
)}
{/* Subtle loading indicator */}
<div className="absolute top-0 left-0 right-0 h-1 bg-muted overflow-hidden rounded-full">
<div className="h-full bg-primary w-1/3 animate-[shimmer_2s_ease-in-out_infinite]"
<div className="h-full bg-primary w-1/3 animate-[shimmer_2s_ease-in-out_infinite]"
style={{
background: 'linear-gradient(90deg, transparent, hsl(var(--primary)), transparent)',
backgroundSize: '200% 100%',
@@ -164,7 +164,7 @@ function AdminComponentSkeleton({ showSlowWarning = false }: { showSlowWarning?:
}}
/>
</div>
{/* Header skeleton */}
<div className="flex justify-between items-center">
<div className="space-y-2">
@@ -181,9 +181,9 @@ function AdminComponentSkeleton({ showSlowWarning = false }: { showSlowWarning?:
{/* Metric cards grid skeleton */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
<Card
key={i}
className="overflow-hidden animate-in fade-in slide-in-from-bottom-4"
<Card
key={i}
className="overflow-hidden animate-in fade-in slide-in-from-bottom-4 border-border/40 bg-background/50 backdrop-blur-sm shadow-sm"
style={{
animationDelay: `${i * 50}ms`,
animationDuration: '400ms',
@@ -227,14 +227,14 @@ function AdminComponentSkeleton({ showSlowWarning = false }: { showSlowWarning?:
}
// Suspense wrapper with timeout
function SuspenseWithTimeout({
children,
fallback,
function SuspenseWithTimeout({
children,
fallback,
timeout = 5000,
timeoutFallback
}: {
children: ReactNode;
fallback: ReactNode;
timeoutFallback
}: {
children: ReactNode;
fallback: ReactNode;
timeout?: number;
timeoutFallback?: ReactNode;
}) {
@@ -258,7 +258,7 @@ function SuspenseWithTimeout({
// Loading skeleton for management cards
function ManagementCardsSkeleton({ showSlowWarning = false }: { showSlowWarning?: boolean }) {
return (
<div
<div
className="grid gap-4 lg:gap-6 sm:grid-cols-2 lg:grid-cols-3 items-stretch relative"
role="status"
aria-label="Loading management tools"
@@ -277,7 +277,7 @@ function ManagementCardsSkeleton({ showSlowWarning = false }: { showSlowWarning?
)}
{/* Subtle loading indicator */}
<div className="absolute -top-6 left-0 right-0 h-1 bg-muted overflow-hidden rounded-full">
<div className="h-full bg-primary w-1/3"
<div className="h-full bg-primary w-1/3"
style={{
background: 'linear-gradient(90deg, transparent, hsl(var(--primary)), transparent)',
backgroundSize: '200% 100%',
@@ -286,9 +286,9 @@ function ManagementCardsSkeleton({ showSlowWarning = false }: { showSlowWarning?
/>
</div>
{[1, 2, 3, 4].map((i) => (
<Card
key={i}
className="overflow-hidden animate-in fade-in slide-in-from-bottom-4"
<Card
key={i}
className="overflow-hidden animate-in fade-in slide-in-from-bottom-4 border-border/40 bg-background/50 backdrop-blur-sm shadow-sm"
style={{
animationDelay: `${i * 75}ms`,
animationDuration: '400ms',
@@ -311,8 +311,8 @@ function ManagementCardsSkeleton({ showSlowWarning = false }: { showSlowWarning?
/* List items skeleton for list cards */
<>
{[1, 2, 3].map((j) => (
<div
key={j}
<div
key={j}
className="space-y-2 p-3 rounded border border-border/50 animate-in fade-in"
style={{
animationDelay: `${(i - 2) * 75 + j * 50}ms`,
@@ -345,9 +345,9 @@ export default function AdminPage() {
const prefetchTabComponents = (tab: string) => {
// Avoid prefetching if already done
if (prefetchedTabs.has(tab)) return;
const startTime = performance.now();
if (tab === "analytics") {
// Prefetch analytics component
import("@/components/admin/AdminAnalytics")
@@ -355,7 +355,7 @@ export default function AdminPage() {
const loadTime = performance.now() - startTime;
console.log(`[Performance] AdminAnalytics prefetched in ${loadTime.toFixed(2)}ms`);
})
.catch(() => {});
.catch(() => { });
} else if (tab === "management") {
// Prefetch management components
Promise.all([
@@ -368,9 +368,9 @@ export default function AdminPage() {
const loadTime = performance.now() - startTime;
console.log(`[Performance] Management components prefetched in ${loadTime.toFixed(2)}ms`);
})
.catch(() => {});
.catch(() => { });
}
setPrefetchedTabs(prev => new Set(prev).add(tab));
};
@@ -392,26 +392,26 @@ export default function AdminPage() {
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div className="flex items-center justify-between animate-in fade-in slide-in-from-top-2 duration-300">
<div>
<h1 className="text-2xl font-semibold tracking-tight">Admin Dashboard</h1>
<h1 className="text-2xl font-semibold tracking-tight text-foreground">Admin Dashboard</h1>
<p className="text-sm text-muted-foreground mt-1">Platform analytics and vendor management</p>
</div>
<Button asChild variant="outline" size="sm">
<Button asChild variant="outline" size="sm" className="border-border/50 bg-background/50 backdrop-blur-sm hover:bg-background/80 transition-all">
<Link href="/dashboard">Back to Dashboard</Link>
</Button>
</div>
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
<TabsList>
<TabsTrigger
<TabsTrigger
value="analytics"
onMouseEnter={() => handleTabHover("analytics")}
onFocus={() => handleTabFocus("analytics")}
>
Analytics
</TabsTrigger>
<TabsTrigger
<TabsTrigger
value="management"
onMouseEnter={() => handleTabHover("management")}
onFocus={() => handleTabFocus("management")}
@@ -422,7 +422,7 @@ export default function AdminPage() {
<TabsContent value="analytics" className="space-y-6 relative">
<ErrorBoundary componentName="Analytics Dashboard">
<SuspenseWithTimeout
<SuspenseWithTimeout
fallback={<AdminComponentSkeleton />}
timeout={5000}
timeoutFallback={<AdminComponentSkeleton showSlowWarning={true} />}
@@ -436,7 +436,7 @@ export default function AdminPage() {
<TabsContent value="management" className="space-y-6 relative">
<ErrorBoundary componentName="Management Tools">
<SuspenseWithTimeout
<SuspenseWithTimeout
fallback={<ManagementCardsSkeleton />}
timeout={5000}
timeoutFallback={<ManagementCardsSkeleton showSlowWarning={true} />}