diff --git a/client/portal/src/components/ErrorPage.tsx b/client/portal/src/components/ErrorPage.tsx
index 2094a40d..7a072863 100644
--- a/client/portal/src/components/ErrorPage.tsx
+++ b/client/portal/src/components/ErrorPage.tsx
@@ -3,93 +3,187 @@ import { isRouteErrorResponse, useNavigate, useRouteError } from "react-router";
import { Button } from "@/components/ui/button";
+/**
+ * Static rather than the super admin's runtime `contact_email`: this page is
+ * the router's error boundary, so it has to render when the API, the session,
+ * or the route that would have loaded that setting is exactly what failed.
+ */
+const SUPPORT_EMAIL = "hello@hackutd.co";
+
type ErrorCopy = {
status: string;
+ /** In-world HUD label. The plain-language title carries the real meaning. */
+ label: string;
title: string;
message: string;
+ /** Raw error text, surfaced only as a trace the hacker can quote to us. */
+ detail?: string;
+};
+
+const NOT_FOUND: ErrorCopy = {
+ status: "404",
+ label: "Signal lost",
+ title: "Page not found.",
+ message: "The page you're looking for doesn't exist or may have moved.",
};
function describeError(error: unknown): ErrorCopy {
+ // The catch-all `*` route renders this page as an ordinary element rather
+ // than as an error boundary, so a mistyped URL arrives with no error at all.
+ // That is a 404, not the unexpected-failure case below.
+ if (error == null) return NOT_FOUND;
+
if (isRouteErrorResponse(error)) {
if (error.status === 404) {
- return {
- status: "404",
- title: "Page not found",
- message: "The page you're looking for doesn't exist or may have moved.",
- };
+ return NOT_FOUND;
}
if (error.status === 401) {
return {
status: "401",
- title: "Not signed in",
+ label: "Identity unverified",
+ title: "Not signed in.",
message: "You need to sign in to view this page.",
};
}
if (error.status === 403) {
return {
status: "403",
- title: "Access denied",
+ label: "Access denied",
+ title: "Clearance required.",
message: "You don't have permission to access this page.",
};
}
return {
status: String(error.status),
- title: error.statusText || "Something went wrong",
+ label: "System fault",
+ title: "Something broke.",
message:
"An unexpected error occurred while loading this page. Please try again.",
+ detail: error.statusText || undefined,
};
}
return {
status: "500",
- title: "uh oh...",
+ label: "System fault",
+ title: "Something broke.",
message:
- error instanceof Error && error.message
- ? error.message
- : "An unexpected error occurred. Please try again, or head back home.",
+ // Non-breaking space keeps the em dash off the start of a wrapped line.
+ "An unexpected error occurred. Try again, or head back home — this one is on us, not you.",
+ detail: error instanceof Error && error.message ? error.message : undefined,
};
}
export function ErrorPage() {
const error = useRouteError();
const navigate = useNavigate();
- const { status, title, message } = describeError(error);
+ const { status, label, title, message, detail } = describeError(error);
return (
-
-
-
-
-
- Error {status}
-
-
- {title}
-
-
- {message}
-
-
+
+
+
+
+ {/* HUD rail — atmosphere only, never the carrier of meaning. */}
+
+ HackUTD // Secure portal
+ MMXXVI
+
+
+ HACKUTD // ZERO DAY
+
+
+
+
+
+
+
+ {label} // {status}
+
+
+
+
+
+
+
+
+
+ {/* Chromatic split — one deliberate glitch artifact, held still. */}
+
+ {status}
+
+
+ {title}
+
+
+ {message}
+
+
+
+ {detail && (
+
+
+ Trace
+
+
+ {detail}
+
+
+ )}
+
+
+
+
+
-
-
-
+
+
+ Still stuck?
+
+
+ If you think this is a real issue, reach out at{" "}
+
+ {SUPPORT_EMAIL}
+ {" "}
+ and we'll take a look.
+