/** * ErrorMessage - Error display components for web * * Components: * - ErrorMessage: Inline error with optional retry * - FullScreenError: Full page error state * - ErrorToast: Dismissible error notification * - FieldError: Form field validation error * * Features: * - Multiple severity levels * - Retry and dismiss actions * - Accessible ARIA labels * - Tailwind CSS styling */ import { cn } from '@/lib/utils'; // Error severity types export type ErrorSeverity = 'error' | 'warning' | 'info'; /** * ErrorMessage - Inline error message with icon and optional actions * * @example * ```tsx * refetch()} * /> * ``` */ interface ErrorMessageProps { message: string; severity?: ErrorSeverity; onRetry?: () => void; onDismiss?: () => void; className?: string; } const severityStyles = { error: { container: 'bg-red-50 border-red-200 text-red-800', icon: 'text-red-500', button: 'text-red-600 hover:text-red-700 hover:bg-red-100', }, warning: { container: 'bg-yellow-50 border-yellow-200 text-yellow-800', icon: 'text-yellow-500', button: 'text-yellow-600 hover:text-yellow-700 hover:bg-yellow-100', }, info: { container: 'bg-blue-50 border-blue-200 text-blue-800', icon: 'text-blue-500', button: 'text-blue-600 hover:text-blue-700 hover:bg-blue-100', }, }; export function ErrorMessage({ message, severity = 'error', onRetry, onDismiss, className, }: ErrorMessageProps) { const styles = severityStyles[severity]; return (
{/* Icon */} {/* Message */}

{message}

{/* Actions */}
{onRetry && ( )} {onDismiss && ( )}
); } /** * FullScreenError - Full page error state with icon and actions * * @example * ```tsx * if (error) { * return ( * refetch()} * /> * ); * } * ``` */ interface FullScreenErrorProps { title?: string; message: string; icon?: 'error' | 'offline' | 'notFound'; onRetry?: () => void; onBack?: () => void; retryLabel?: string; backLabel?: string; } const iconPaths = { error: 'M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z', offline: 'M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z', notFound: 'M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M12 12h.01M12 12h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z', }; export function FullScreenError({ title = 'Something went wrong', message, icon = 'error', onRetry, onBack, retryLabel = 'Try Again', backLabel = 'Go Back', }: FullScreenErrorProps) { return (
{/* Icon */}
{/* Title */}

{title}

{/* Message */}

{message}

{/* Actions */}
{onRetry && ( )} {onBack && ( )}
); } /** * FieldError - Inline form field validation error * * @example * ```tsx * * {error && } * ``` */ interface FieldErrorProps { message: string; className?: string; } export function FieldError({ message, className }: FieldErrorProps) { return (

{message}

); } /** * ErrorBoundary fallback component * * @example * ```tsx * }> * * * ``` */ interface ErrorBoundaryFallbackProps { error?: Error; resetError?: () => void; } export function ErrorBoundaryFallback({ error, resetError, }: ErrorBoundaryFallbackProps) { return ( ); } /** * EmptyState - Component for empty data states (not strictly an error) * * @example * ```tsx * {items.length === 0 && ( * setShowModal(true)} * /> * )} * ``` */ interface EmptyStateProps { title: string; message?: string; icon?: React.ReactNode; actionLabel?: string; onAction?: () => void; className?: string; } export function EmptyState({ title, message, icon, actionLabel, onAction, className, }: EmptyStateProps) { return (
{/* Icon */} {icon && (
{icon}
)} {/* Title */}

{title}

{/* Message */} {message && (

{message}

)} {/* Action */} {actionLabel && onAction && ( )}
); }