From 0819191cb9adbea6cdbfe6ab33eeb4310e648271 Mon Sep 17 00:00:00 2001 From: JerryVincent Date: Wed, 4 Mar 2026 14:06:14 +0100 Subject: [PATCH] This commit enhances the error-message component to show more details about the error. --- app/components/error-message.tsx | 227 ++++++++++++++++-- app/routes/device.$deviceId.edit.security.tsx | 3 +- public/locales/de/common.json | 12 +- public/locales/en/common.json | 12 +- 4 files changed, 231 insertions(+), 23 deletions(-) diff --git a/app/components/error-message.tsx b/app/components/error-message.tsx index 26618924..1fc33814 100644 --- a/app/components/error-message.tsx +++ b/app/components/error-message.tsx @@ -1,27 +1,214 @@ -import { X } from 'lucide-react' -import { useNavigate } from 'react-router' -import { Alert, AlertDescription } from './ui/alert' +import { + AlertCircle, + ArrowLeft, + Home, + RefreshCw, + ServerCrash, + FileQuestion, + ShieldX, + WifiOff, +} from 'lucide-react' +import { useTranslation } from 'react-i18next' +import { useNavigate, useRouteError, isRouteErrorResponse } from 'react-router' +import { Button } from './ui/button' +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from './ui/card' + +type ErrorType = 'not_found' | 'forbidden' | 'server' | 'network' | 'generic' export default function ErrorMessage() { - let navigate = useNavigate() + const navigate = useNavigate() + const error = useRouteError() + const { t } = useTranslation('common') + const goBack = () => navigate(-1) + const goHome = () => navigate('/') + const refresh = () => window.location.reload() + + const getErrorInfo = (): { + type: ErrorType + status?: number + title: string + message: string + } => { + if (isRouteErrorResponse(error)) { + const status = error.status + const actualMessage = error.data?.message || error.data + + if (status === 404) { + return { + type: 'not_found', + status, + title: t('error_not_found_title'), + message: actualMessage || t('error_generic_message'), + } + } + + if (status === 403) { + return { + type: 'forbidden', + status, + title: t('error_forbidden_title'), + message: actualMessage || t('error_generic_message'), + } + } + + if (status >= 500) { + return { + type: 'server', + status, + title: t('error_server_title'), + message: actualMessage || t('error_generic_message'), + } + } + + return { + type: 'generic', + status, + title: `${status} ${error.statusText}`, + message: actualMessage || t('error_generic_message'), + } + } + + if (typeof error === 'string') { + const errorLower = error.toLowerCase() + + let type: ErrorType = 'generic' + if (errorLower.includes('not found')) { + type = 'not_found' + } else if ( + errorLower.includes('forbidden') || + errorLower.includes('permission') + ) { + type = 'forbidden' + } + + return { + type, + title: t('error_occurred'), + message: error, + } + } + + if (error instanceof Error) { + let type: ErrorType = 'generic' + + if ( + error.message.includes('fetch') || + error.message.includes('network') + ) { + type = 'network' + } + + return { + type, + title: t('error_occurred'), + message: error.message, + } + } + + return { + type: 'generic', + title: t('error_occurred'), + message: t('error_generic_message'), + } + } + + const { type, status, title, message } = getErrorInfo() + + const getIcon = () => { + const iconClass = 'h-12 w-12' + + switch (type) { + case 'not_found': + return + case 'forbidden': + return + case 'server': + return + case 'network': + return + default: + return + } + } + + const getGradient = () => { + switch (type) { + case 'not_found': + return 'from-amber-50 to-orange-50 dark:from-amber-950/20 dark:to-orange-950/20' + case 'forbidden': + return 'from-red-50 to-pink-50 dark:from-red-950/20 dark:to-pink-950/20' + case 'server': + return 'from-red-50 to-rose-50 dark:from-red-950/20 dark:to-rose-950/20' + case 'network': + return 'from-gray-50 to-slate-50 dark:from-gray-950/20 dark:to-slate-950/20' + default: + return 'from-blue-50 to-indigo-50 dark:from-blue-950/20 dark:to-indigo-950/20' + } + } return ( - -
- { - void goBack() - }} - /> -
-

- Oh no, this shouldn't happen, but don't worry, our team is on the case! -

- -

Add some info here.

-
-
+
+ + +
+ {getIcon()} +
+ {status && ( +

+ {status} +

+ )} + {title} + {message} +
+ + +
+

+ {t('error_help_text')} +

+
+
+ + + + + {(type === 'server' || type === 'network') && ( + + )} + +
+
) } diff --git a/app/routes/device.$deviceId.edit.security.tsx b/app/routes/device.$deviceId.edit.security.tsx index 365ed84e..ad4cf4b5 100644 --- a/app/routes/device.$deviceId.edit.security.tsx +++ b/app/routes/device.$deviceId.edit.security.tsx @@ -15,6 +15,7 @@ import { Form, useLoaderData, type ActionFunctionArgs, + data, } from 'react-router' import { Checkbox } from '@/components/ui/checkbox' import ErrorMessage from '~/components/error-message' @@ -35,7 +36,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) { if (typeof deviceId !== 'string') throw 'deviceID not found' const t = (await getDevice({ id: deviceId }))?.apiKey - if (!t) throw 'device not found' + if (!t) throw data({ message: 'Device not found!'}, {status: 404}) const device = await getDevice({ id: deviceId }) return { key: t, deviceAuthEnabled: device?.useAuth ?? false } diff --git a/public/locales/de/common.json b/public/locales/de/common.json index 502e899d..eee8431c 100644 --- a/public/locales/de/common.json +++ b/public/locales/de/common.json @@ -1,4 +1,14 @@ { "greeting": "Hallo", - "backToDashboardNavText": "Zurück zum Dashboard" + "backToDashboardNavText": "Zurück zum Dashboard", + "error_occurred": "Ein Fehler ist aufgetreten", + "error_not_found_title": "Seite nicht gefunden", + "error_forbidden_title": "Zugriff verweigert", + "error_server_title": "Serverfehler", + "error_network_title": "Verbindungsfehler", + "error_generic_message": "Etwas Unerwartetes ist passiert. Bitte versuchen Sie es erneut.", + "error_help_text": "Wenn dieses Problem weiterhin besteht, wenden Sie sich bitte an unser Support-Team.", + "go_back": "Zurück", + "go_home": "Zur Startseite", + "try_again": "Erneut versuchen" } diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 75d33155..553357e3 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -1,4 +1,14 @@ { "greeting": "Hello", - "backToDashboardNavText": "Back to Dashboard" + "backToDashboardNavText": "Back to Dashboard", + "error_occurred": "An error occurred", + "error_not_found_title": "Page not found", + "error_forbidden_title": "Access denied", + "error_server_title": "Server error", + "error_network_title": "Connection error", + "error_generic_message": "Something unexpected happened. Please try again.", + "error_help_text": "If this problem persists, please contact our support team.", + "go_back": "Go back", + "go_home": "Go home", + "try_again": "Try again" }