import React from 'react'; import { useLocalize } from '~/hooks'; import { Button } from '~/components/ui'; import { cn } from '~/utils'; // Comprehensive error type that handles all possible error structures type ApiError = | string | Error | { message?: string; status?: number; code?: string; response?: { data?: { userMessage?: string; suggestion?: string; message?: string; }; status?: number; }; data?: { userMessage?: string; suggestion?: string; message?: string; }; }; interface ErrorDisplayProps { error: ApiError; onRetry?: () => void; context?: { searchQuery?: string; category?: string; }; } /** * User-friendly error display component with actionable suggestions */ export const ErrorDisplay: React.FC = ({ error, onRetry, context }) => { const localize = useLocalize(); // Type guards const isErrorObject = (err: ApiError): err is { [key: string]: unknown } => { return typeof err === 'object' && err !== null && !(err instanceof Error); }; const isErrorInstance = (err: ApiError): err is Error => { return err instanceof Error; }; // Extract user-friendly error information const getErrorInfo = (): { title: string; message: string; suggestion: string } => { // Handle different error types let errorData: unknown; if (typeof error === 'string') { errorData = { message: error }; } else if (isErrorInstance(error)) { errorData = { message: error.message }; } else if (isErrorObject(error)) { // Handle axios error response structure errorData = (error as any)?.response?.data || (error as any)?.data || error; } else { errorData = error; } // Use user-friendly message from backend if available if (errorData && typeof errorData === 'object' && (errorData as any)?.userMessage) { return { title: getContextualTitle(), message: (errorData as any).userMessage, suggestion: (errorData as any).suggestion || localize('com_agents_error_suggestion_generic'), }; } // Handle network errors const errorMessage = isErrorInstance(error) ? error.message : isErrorObject(error) && (error as any)?.message ? (error as any).message : ''; const errorCode = isErrorObject(error) ? (error as any)?.code : ''; if (errorCode === 'NETWORK_ERROR' || errorMessage?.includes('Network Error')) { return { title: localize('com_agents_error_network_title'), message: localize('com_agents_error_network_message'), suggestion: localize('com_agents_error_network_suggestion'), }; } // Handle specific HTTP status codes const status = isErrorObject(error) ? (error as any)?.response?.status : null; if (status) { if (status === 404) { return { title: localize('com_agents_error_not_found_title'), message: getNotFoundMessage(), suggestion: localize('com_agents_error_not_found_suggestion'), }; } if (status === 400) { return { title: localize('com_agents_error_invalid_request'), message: (errorData as any)?.userMessage || localize('com_agents_error_bad_request_message'), suggestion: localize('com_agents_error_bad_request_suggestion'), }; } if (status >= 500) { return { title: localize('com_agents_error_server_title'), message: localize('com_agents_error_server_message'), suggestion: localize('com_agents_error_server_suggestion'), }; } } // Fallback to generic error return { title: localize('com_agents_error_title'), message: localize('com_agents_error_generic'), suggestion: localize('com_agents_error_suggestion_generic'), }; }; /** * Get contextual title based on current operation */ const getContextualTitle = (): string => { if (context?.searchQuery) { return localize('com_agents_error_search_title'); } if (context?.category) { return localize('com_agents_error_category_title'); } return localize('com_agents_error_title'); }; /** * Get context-specific not found message */ const getNotFoundMessage = (): string => { if (context?.searchQuery) { return localize('com_agents_search_no_results', { query: context.searchQuery }); } if (context?.category && context.category !== 'all') { return localize('com_agents_category_empty', { category: context.category }); } return localize('com_agents_error_not_found_message'); }; const { title, message, suggestion } = getErrorInfo(); return (
{/* Error icon with proper accessibility */}
{/* Error content with proper headings and structure */}

{title}

{message}

💡 {suggestion}

{/* Retry button with enhanced accessibility */} {onRetry && (
)}
); }; export default ErrorDisplay;