diff --git a/src/views/Error.jsx b/src/views/Error.jsx
index b140ed2..10a06e1 100644
--- a/src/views/Error.jsx
+++ b/src/views/Error.jsx
@@ -1,52 +1,226 @@
-import { HomeRounded, Login } from '@mui/icons-material'
-import { Box, Button, CircularProgress, Container, Typography } from '@mui/joy'
-import { Link } from 'react-router-dom'
-import Logo from '../Logo' // Adjust the import path as necessary
+import {
+ BugReportRounded,
+ CloudOffRounded,
+ ContentCopyRounded,
+ ErrorRounded,
+ ExpandMoreRounded,
+ HomeRounded,
+ LockRounded,
+ RefreshRounded,
+ SearchOffRounded,
+} from '@mui/icons-material'
+import { Box, Button, IconButton, Snackbar, Typography } from '@mui/joy'
+import { useState } from 'react'
+import { Link, useRouteError } from 'react-router-dom'
+
+const getErrorKind = error => {
+ if (!error)
+ return { label: 'Unknown Error', color: 'danger', Icon: ErrorRounded }
+ const status = error?.status ?? error?.response?.status
+ if (status === 404)
+ return {
+ label: '404 · Not Found',
+ color: 'warning',
+ Icon: SearchOffRounded,
+ }
+ if (status === 401 || status === 403)
+ return {
+ label: `${status} · Unauthorized`,
+ color: 'warning',
+ Icon: LockRounded,
+ }
+ if (status >= 500)
+ return {
+ label: `${status} · Server Error`,
+ color: 'danger',
+ Icon: CloudOffRounded,
+ }
+ if (error?.name === 'TypeError')
+ return { label: 'Runtime Error', color: 'danger', Icon: BugReportRounded }
+ if (error?.name === 'SyntaxError')
+ return { label: 'Syntax Error', color: 'danger', Icon: BugReportRounded }
+ return { label: 'Unexpected Error', color: 'danger', Icon: ErrorRounded }
+}
+
+const safeMessage = error => {
+ const msg = error?.message ?? error?.statusText
+ if (!msg || msg === '[object Object]') return null
+ return msg
+}
+
+const buildErrorText = (error, url) => {
+ const lines = [
+ `URL: ${url}`,
+ `Time: ${new Date().toISOString()}`,
+ `Error: ${safeMessage(error) ?? String(error)}`,
+ ]
+ if (error?.stack) lines.push(`\nStack:\n${error.stack}`)
+ return lines.join('\n')
+}
const Error = () => {
+ const error = useRouteError()
+ const [showDetails, setShowDetails] = useState(false)
+ const [copied, setCopied] = useState(false)
+
+ const { color, Icon } = getErrorKind(error)
+ const message = safeMessage(error)
+ const url = window.location.href
+
+ const handleCopy = () => {
+ navigator.clipboard.writeText(buildErrorText(error, url)).then(() => {
+ setCopied(true)
+ })
+ }
+
return (
-
+
+ {/* Decorative dots */}
+
+
+
+
+ {/* Icon with concentric rings */}
+
-
-
-
- Ops, something went wrong
-
-
- if you think this is a mistake, please contact us or{' '}
-
- open issue here
- {' '}
-
+
+
+
+
+
+
+ {/* Title */}
+
+ Something went wrong
+
+
+ {/* Error message */}
+
+ {message ??
+ 'An unexpected error occurred. Try reloading — it usually fixes it.'}
+
+
+ {/* Primary CTA */}
+ }
+ onClick={() => window.location.reload()}
+ sx={{ width: '100%', mb: 2 }}
+ >
+ Try again
+
+
+ {/* Secondary actions */}
+
}
>
@@ -55,16 +229,108 @@ const Error = () => {
}
>
Login
-
+
+ {/* Report hint + collapsible details */}
+
+
+ If this keeps happening,{' '}
+
+ open an issue
+ {' '}
+ and include the error details below.
+
+
+ {(error?.stack || message) && (
+ <>
+
+
+ {showDetails && (
+
+
+
+
+
+ {buildErrorText(error, url)}
+
+
+ )}
+ >
+ )}
+
+
+ setCopied(false)}
+ anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
+ size='sm'
+ >
+ Error details copied to clipboard
+
+
)
}