import { ReactNode } from 'react'; import { Skeleton } from '@/components/ui/skeleton'; import { Card, CardContent } from '@/components/ui/card'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Loader2, AlertCircle } from 'lucide-react'; interface LoadingGateProps { /** Whether data is still loading */ isLoading: boolean; /** Optional error to display */ error?: Error | null; /** Content to render when loaded */ children: ReactNode; /** Loading variant */ variant?: 'skeleton' | 'spinner' | 'card'; /** Number of skeleton items (for skeleton variant) */ skeletonCount?: number; /** Custom loading message */ loadingMessage?: string; /** Custom error message */ errorMessage?: string; } /** * Reusable loading and error state wrapper * * Handles common loading patterns: * - Skeleton loaders * - Spinner with message * - Card-based loading states * - Error display * * @example * ```tsx * * * * ``` */ export function LoadingGate({ isLoading, error, children, variant = 'skeleton', skeletonCount = 3, loadingMessage = 'Loading...', errorMessage, }: LoadingGateProps) { // Error state if (error) { return ( Error {errorMessage || error.message || 'An unexpected error occurred'} ); } // Loading state if (isLoading) { switch (variant) { case 'spinner': return (

{loadingMessage}

); case 'card': return ( {Array.from({ length: skeletonCount }).map((_, i) => (
))}
); case 'skeleton': default: return (
{Array.from({ length: skeletonCount }).map((_, i) => (
))}
); } } // Loaded state return <>{children}; }