'use client' import * as React from 'react' import { AlertCircle } from 'lucide-react' import { useTranslations } from 'next-intl' import { Button } from '@/components/ui/button' import { Skeleton } from '@/components/ui/skeleton' import { cn } from '@/lib/utils' interface DataStateProps { loading: boolean error: string | null /** When true (and not loading/error), render `empty` instead of `children`. */ isEmpty?: boolean /** Retry handler: typically `useFetch().refetch`. Shows a retry button. */ onRetry?: () => void /** Loading placeholder. Defaults to three skeleton rows. */ skeleton?: React.ReactNode /** Shown when `isEmpty`. Pass an `EmptyState` / preset (e.g. ``). */ empty?: React.ReactNode children: React.ReactNode className?: string } /** * Renders the loading / error / empty / ready states for a data-driven section, * so callers stop hand-rolling that branch every time. * * Pairs with `useFetch`: * * @example * const { data, loading, error, refetch } = useFetch(url, { select: b => b.data }) * return ( * } * > * * * ) * * Loading uses the `Skeleton` primitive; empty expects an `EmptyState`; the * error branch uses the only chrome-permitted semantic colour (`destructive`). */ export function DataState({ loading, error, isEmpty = false, onRetry, skeleton, empty, children, className, }: DataStateProps) { const t = useTranslations('common') if (loading) { return (
{skeleton ?? (
)}
) } if (error) { return (
) } if (isEmpty) { return
{empty}
} return <>{children} }