mirror of
https://github.com/joinmarket-webui/jam.git
synced 2026-08-15 12:50:48 +02:00
94 lines
2.9 KiB
TypeScript
94 lines
2.9 KiB
TypeScript
import { t } from 'i18next'
|
|
import { Trans, useTranslation } from 'react-i18next'
|
|
import { useRouteError } from 'react-router-dom'
|
|
import { Alert, AlertDescription } from '@/components/ui/alert'
|
|
import PageTitle from '@/components/ui/jam/PageTitle'
|
|
|
|
interface ErrorViewProps {
|
|
title: string
|
|
subtitle: string
|
|
reason: string
|
|
stacktrace?: string
|
|
}
|
|
|
|
function ErrorView({ title, subtitle, reason, stacktrace }: ErrorViewProps) {
|
|
return (
|
|
<div className="mx-auto max-w-4xl space-y-3 p-4">
|
|
<PageTitle title={title} subtitle={subtitle} variant="error" />
|
|
<p>
|
|
<Trans i18nKey="error_page.report_bug">
|
|
Please{' '}
|
|
<a
|
|
href="https://github.com/joinmarket-webui/jam/issues/new?labels=bug&template=bug_report.md"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="font-semibold underline hover:no-underline"
|
|
>
|
|
open an issue on GitHub
|
|
</a>{' '}
|
|
for this error to be reviewed and resolved in an upcoming version.
|
|
</Trans>
|
|
</p>
|
|
|
|
<div className="my-4">
|
|
<h6 className="font-semibold">{t('error_page.heading_reason')}</h6>
|
|
<Alert variant="destructive" className="overflow-x-auto">
|
|
<AlertDescription className="min-w-0 break-words">{reason}</AlertDescription>
|
|
</Alert>
|
|
</div>
|
|
|
|
{stacktrace && (
|
|
<div className="my-4">
|
|
<h6 className="font-semibold">{t('error_page.heading_stacktrace')}</h6>
|
|
<pre className="max-w-full overflow-x-auto rounded-lg border p-2">
|
|
<code>{stacktrace}</code>
|
|
</pre>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function UnknownError({ error }: { error: unknown }) {
|
|
const { t } = useTranslation()
|
|
|
|
const title = t('error_page.unknown_error.title')
|
|
const subtitle = t('error_page.unknown_error.subtitle')
|
|
if (!error || typeof error !== 'object') {
|
|
return <ErrorView title={title} subtitle={subtitle} reason={t('global.errors.reason_unknown')} />
|
|
}
|
|
|
|
const reason = 'message' in error && typeof error.message === 'string' ? error.message : undefined
|
|
const stacktrace = 'stack' in error && typeof error.stack === 'string' ? error.stack : undefined
|
|
return (
|
|
<ErrorView
|
|
title={title}
|
|
subtitle={subtitle}
|
|
reason={reason || t('global.errors.reason_unknown')}
|
|
stacktrace={stacktrace}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function ErrorWithDetails({ error }: { error: Error }) {
|
|
const { t } = useTranslation()
|
|
|
|
return (
|
|
<ErrorView
|
|
title={t('error_page.error_with_details.title')}
|
|
subtitle={t('error_page.error_with_details.subtitle')}
|
|
reason={error.message || t('global.errors.reason_unknown')}
|
|
stacktrace={error.stack}
|
|
/>
|
|
)
|
|
}
|
|
|
|
export default function ErrorPage() {
|
|
const error = useRouteError()
|
|
|
|
if (error instanceof Error) {
|
|
return <ErrorWithDetails error={error} />
|
|
} else {
|
|
return <UnknownError error={error} />
|
|
}
|
|
}
|