Add robust error boundaries and improved skeletons to dashboard
Introduces reusable error boundary and suspense timeout components across dashboard pages for better error handling and user feedback. Enhances loading skeletons with subtle progress indicators, animation, and slow-loading warnings. All dynamic imports now include error handling and improved fallback skeletons, and a shared DashboardContentWrapper is added for consistent dashboard content loading experience.
This commit is contained in:
@@ -17,23 +17,59 @@ import {
|
||||
import dynamic from "next/dynamic";
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
|
||||
// Lazy load components
|
||||
const ShippingModal = dynamic(() => import("@/components/modals/shipping-modal").then(mod => ({ default: mod.ShippingModal })), {
|
||||
loading: () => <div>Loading...</div>
|
||||
// Lazy load components with error handling
|
||||
const ShippingModal = dynamic(() => import("@/components/modals/shipping-modal").then(mod => ({ default: mod.ShippingModal })).catch((err) => {
|
||||
console.error("Failed to load ShippingModal:", err);
|
||||
throw err;
|
||||
}), {
|
||||
loading: () => (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm">
|
||||
<Card className="w-full max-w-md m-4 animate-in fade-in zoom-in-95 duration-300">
|
||||
<CardHeader>
|
||||
<Skeleton className="h-6 w-48" />
|
||||
<Skeleton className="h-4 w-64 mt-2" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{[...Array(3)].map((_, i) => (
|
||||
<div key={i} className="space-y-2">
|
||||
<Skeleton className="h-4 w-24" />
|
||||
<Skeleton className="h-10 w-full rounded-md" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
|
||||
const ShippingTable = dynamic(() => import("@/components/tables/shipping-table").then(mod => ({ default: mod.ShippingTable })), {
|
||||
const ShippingTable = dynamic(() => import("@/components/tables/shipping-table").then(mod => ({ default: mod.ShippingTable })).catch((err) => {
|
||||
console.error("Failed to load ShippingTable:", err);
|
||||
throw err;
|
||||
}), {
|
||||
loading: () => <ShippingTableSkeleton />
|
||||
});
|
||||
|
||||
// Loading skeleton for shipping table
|
||||
function ShippingTableSkeleton() {
|
||||
return (
|
||||
<Card>
|
||||
<Card className="animate-in fade-in duration-500 relative">
|
||||
{/* Subtle loading indicator */}
|
||||
<div className="absolute top-0 left-0 right-0 h-1 bg-muted overflow-hidden rounded-t-lg">
|
||||
<div className="h-full bg-primary w-1/3"
|
||||
style={{
|
||||
background: 'linear-gradient(90deg, transparent, hsl(var(--primary)), transparent)',
|
||||
backgroundSize: '200% 100%',
|
||||
animation: 'shimmer 2s ease-in-out infinite',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<Skeleton className="h-6 w-32" />
|
||||
<Skeleton className="h-9 w-24" />
|
||||
<Skeleton className="h-9 w-24 rounded-md" />
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
@@ -41,19 +77,35 @@ function ShippingTableSkeleton() {
|
||||
<div className="border-b p-4">
|
||||
<div className="flex items-center gap-4">
|
||||
{['Method Name', 'Price', 'Actions'].map((header, i) => (
|
||||
<Skeleton key={i} className="h-4 w-20 flex-1" />
|
||||
<Skeleton
|
||||
key={i}
|
||||
className="h-4 w-20 flex-1 animate-in fade-in"
|
||||
style={{
|
||||
animationDelay: `${i * 50}ms`,
|
||||
animationDuration: '300ms',
|
||||
animationFillMode: 'both',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{[...Array(4)].map((_, i) => (
|
||||
<div key={i} className="border-b last:border-b-0 p-4">
|
||||
<div
|
||||
key={i}
|
||||
className="border-b last:border-b-0 p-4 animate-in fade-in"
|
||||
style={{
|
||||
animationDelay: `${200 + i * 50}ms`,
|
||||
animationDuration: '300ms',
|
||||
animationFillMode: 'both',
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<Skeleton className="h-4 w-32 flex-1" />
|
||||
<Skeleton className="h-4 w-16 flex-1" />
|
||||
<div className="flex gap-2 flex-1">
|
||||
<Skeleton className="h-8 w-16" />
|
||||
<Skeleton className="h-8 w-16" />
|
||||
<Skeleton className="h-8 w-16 rounded-md" />
|
||||
<Skeleton className="h-8 w-16 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user