src
This commit is contained in:
parent
13e2d46d6f
commit
afe5879b62
3 changed files with 129 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -31,7 +31,6 @@ develop-eggs/
|
|||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
|
|
|
|||
123
admin/src/lib/error-utils.ts
Normal file
123
admin/src/lib/error-utils.ts
Normal file
|
|
@ -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<ApiErrorResponse>
|
||||
|
||||
// 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<ApiErrorResponse>
|
||||
|
||||
// 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
|
||||
}
|
||||
6
admin/src/lib/utils.ts
Normal file
6
admin/src/lib/utils.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { type ClassValue, clsx } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
Loading…
Reference in a new issue