From afe5879b62ee60d0dd59adb36a2ec282d2870dfc Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 7 Jan 2026 00:10:50 +0300 Subject: [PATCH] src --- .gitignore | 1 - admin/src/lib/error-utils.ts | 123 +++++++++++++++++++++++++++++++++++ admin/src/lib/utils.ts | 6 ++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 admin/src/lib/error-utils.ts create mode 100644 admin/src/lib/utils.ts diff --git a/.gitignore b/.gitignore index d1d1883..38afb08 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,6 @@ develop-eggs/ downloads/ eggs/ .eggs/ -lib/ lib64/ parts/ sdist/ diff --git a/admin/src/lib/error-utils.ts b/admin/src/lib/error-utils.ts new file mode 100644 index 0000000..40da834 --- /dev/null +++ b/admin/src/lib/error-utils.ts @@ -0,0 +1,123 @@ +import type { AxiosError } from 'axios' + +export interface ApiErrorResponse { + error?: string + message?: string + details?: string + field?: string + code?: string +} + +/** + * Formats an API error into a user-friendly message + */ +export function formatApiError(error: unknown): string { + const axiosError = error as AxiosError + + // Network error (no response from server) + if (!axiosError.response) { + if (axiosError.code === 'ECONNABORTED') { + return 'Request timeout: The server took too long to respond. Please check your connection and try again.' + } + if (axiosError.message?.includes('Network Error')) { + return 'Network error: Unable to connect to the server. Please check your internet connection.' + } + return 'Connection error: Unable to reach the server. Please check your connection and try again.' + } + + const status = axiosError.response.status + const data = axiosError.response.data + + // Get error message from response + const message = data?.message || data?.error || 'An unknown error occurred' + + // Add more context based on status code + switch (status) { + case 400: + if (data?.field) { + return `Validation error: ${message} (field: ${data.field})` + } + if (data?.details) { + return `Bad request: ${message}. ${data.details}` + } + return `Invalid request: ${message}` + + case 401: + return 'Authentication required: Please log in again.' + + case 403: + return 'Access denied: You do not have permission to perform this action.' + + case 404: + // Make 404 errors more specific based on the endpoint + { + const url = axiosError.config?.url || '' + if (url.includes('/cards/')) { + return 'Card not found: The requested card does not exist or has been deleted.' + } + if (url.includes('/packs/')) { + return 'Pack not found: The requested pack does not exist or has been deleted.' + } + if (url.includes('/users/')) { + return 'User not found: The requested user does not exist.' + } + return `Resource not found: ${message}` + } + + case 409: + return `Conflict: ${message}. The resource may already exist or be in use.` + + case 422: + if (data?.details) { + return `Validation failed: ${message}. ${data.details}` + } + return `Validation error: ${message}` + + case 429: + return 'Too many requests: Please wait a moment and try again.' + + case 500: + return `Server error: ${message}. Please try again later or contact support if the problem persists.` + + case 502: + return 'Bad gateway: The server is temporarily unavailable. Please try again later.' + + case 503: + return 'Service unavailable: The server is temporarily down for maintenance. Please try again later.' + + case 504: + return 'Gateway timeout: The server took too long to respond. Please try again.' + + default: + return `${message} (Error ${status})` + } +} + +/** + * Gets a detailed error message with additional context for specific operations + */ +export function getDetailedErrorMessage( + error: unknown, + operation: string, + resource?: string +): string { + const baseMessage = formatApiError(error) + const axiosError = error as AxiosError + + // Add operation context + let contextMessage = baseMessage + + if (operation && resource) { + contextMessage = `Failed to ${operation} ${resource}: ${baseMessage}` + } else if (operation) { + contextMessage = `Failed to ${operation}: ${baseMessage}` + } + + // Add field-specific errors if available + if (axiosError.response?.data?.field) { + const field = axiosError.response.data.field + contextMessage += ` (Field: ${field})` + } + + return contextMessage +} diff --git a/admin/src/lib/utils.ts b/admin/src/lib/utils.ts new file mode 100644 index 0000000..d084cca --- /dev/null +++ b/admin/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +}