Improve UX error message

Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
Bryan Frimin
2026-06-05 17:35:15 +02:00
parent a1236f866b
commit caeac0ed1c
5 changed files with 216 additions and 91 deletions

View File

@@ -13,17 +13,14 @@
// PERFORMANCE OF THIS SOFTWARE.
import { useTranslate } from "@probo/i18n";
import { IconPageCross } from "@probo/ui";
import {
Button,
ErrorDetailMessage,
ErrorDetails,
ErrorLayout,
} from "@probo/ui";
import { useEffect, useRef } from "react";
import { useLocation, useRouteError } from "react-router";
const classNames = {
wrapper: "py-10 text-center space-y-2 ",
title: "text-2xl flex gap-2 font-semibold items-center justify-center",
description: "text-base text-txt-tertiary",
detail:
"text-sm text-txt-tertiary font-mono text-start border border-border-low p-2 rounded bg-level-1 mt-2",
};
import { Link, useLocation, useRouteError } from "react-router";
type Props = {
resetErrorBoundary?: () => void;
@@ -31,11 +28,16 @@ type Props = {
};
export function PageError({ resetErrorBoundary, error: propsError }: Props) {
const error = useRouteError() ?? propsError;
const routeError = useRouteError();
const error = routeError ?? propsError;
const { __ } = useTranslate();
const location = useLocation();
const baseLocation = useRef(location);
const isFullPage = Boolean(routeError ?? propsError);
const isEmbeddedNotFound = !isFullPage
&& /^\/organizations\/[^/]+/.test(location.pathname);
// Reset error boundary on page change
useEffect(() => {
if (
@@ -46,44 +48,49 @@ export function PageError({ resetErrorBoundary, error: propsError }: Props) {
}
}, [location, resetErrorBoundary]);
const actions = (
<Button asChild>
<Link to="/">{__("Go home")}</Link>
</Button>
);
const layoutProps = {
fullPage: isFullPage || !isEmbeddedNotFound,
showLogo: isFullPage,
actions,
};
if (!error || (error instanceof Error && error.message.includes("PAGE_NOT_FOUND"))) {
return (
<div className={classNames.wrapper}>
<h1 className={classNames.title}>
<IconPageCross size={26} />
{__("Page not found")}
</h1>
<p className={classNames.description}>
{__("The page you are looking for does not exist")}
</p>
</div>
<ErrorLayout
{...layoutProps}
title={__("Page not found")}
description={__("The page you are looking for does not exist.")}
/>
);
}
if (error instanceof Error && error.message.includes("FORBIDDEN")) {
return (
<div className={classNames.wrapper}>
<h1 className={classNames.title}>
<IconPageCross size={26} />
{__("Page not found")}
</h1>
<p className={classNames.description}>
{__("The page you are looking for does not exist")}
</p>
</div>
<ErrorLayout
{...layoutProps}
title={__("Page not found")}
description={__("The page you are looking for does not exist.")}
/>
);
}
return (
<div className={classNames.wrapper}>
<h1 className={classNames.title}>{__("Unexpected error :(")}</h1>
<details>
<summary className={classNames.description}>
{__("Something went wrong")}
</summary>
{error instanceof Error
&& <p className={classNames.detail}>{error.message}</p>}
</details>
</div>
<ErrorLayout
{...layoutProps}
title={__("Something went wrong")}
description={__("We hit an unexpected error. Head back home to continue.")}
>
{error instanceof Error && (
<ErrorDetails summary={__("Technical details")}>
<ErrorDetailMessage>{error.message}</ErrorDetailMessage>
</ErrorDetails>
)}
</ErrorLayout>
);
}