@@ -27,6 +27,10 @@ import {
2727 NewBreadCrumbs ,
2828 NewBreadCrumbsLink ,
2929} from "@thunderstore/cyberstorm" ;
30+ import {
31+ parseUserFacingErrorPayload ,
32+ type UserFacingErrorPayload ,
33+ } from "cyberstorm/utils/errors/userFacingErrorResponse" ;
3034import { DapperTs } from "@thunderstore/dapper-ts" ;
3135import { type CurrentUser } from "@thunderstore/dapper/types" ;
3236
@@ -35,6 +39,7 @@ import { memo, type ReactNode, Suspense, useEffect, useRef } from "react";
3539import { useHydrated } from "remix-utils/use-hydrated" ;
3640import Toast from "@thunderstore/cyberstorm/src/newComponents/Toast" ;
3741import { Footer } from "./commonComponents/Footer/Footer" ;
42+ import { NimbusAwaitErrorElement } from "../cyberstorm/utils/errors/NimbusErrorBoundary" ;
3843import { type RequestConfig } from "@thunderstore/thunderstore-api" ;
3944import { NavigationWrapper } from "./commonComponents/Navigation/NavigationWrapper" ;
4045import { NamespacedStorageManager } from "@thunderstore/ts-api-react" ;
@@ -617,18 +622,36 @@ export function ErrorBoundary() {
617622 console . log ( error ) ;
618623 }
619624 const isResponseError = isRouteErrorResponse ( error ) ;
625+ let payload : UserFacingErrorPayload | null = null ;
626+
627+ if ( isResponseError ) {
628+ payload = parseUserFacingErrorPayload ( error . data ) ;
629+ }
630+
631+ const statusCode = payload ?. status ?? ( isResponseError ? error . status : 500 ) ;
632+ const headline =
633+ payload ?. headline ??
634+ ( isResponseError
635+ ? error . statusText || `Error ${ error . status } `
636+ : "Internal server error" ) ;
637+
638+ const fallbackDescription =
639+ isResponseError && typeof error . data === "string"
640+ ? dedupeDescription ( headline , error . data )
641+ : undefined ;
642+
643+ const description = payload ?. description ?? fallbackDescription ;
644+ const showDefaultFlavor = ! payload && ! isResponseError ;
620645 return (
621646 < div className = "error" >
622- < div
623- className = "error__glitch"
624- data-text = { isResponseError ? error . status : 500 }
625- >
626- < span > { isResponseError ? error . status : 500 } </ span >
647+ < div className = "error__glitch" data-text = { statusCode } >
648+ < span > { statusCode } </ span >
627649 </ div >
628650 < div className = "error__description" >
629- { isResponseError ? error . data : "Internal server error" }
651+ < strong > { headline } </ strong >
652+ { description ? < div > { description } </ div > : null }
630653 </ div >
631- { ! isResponseError && (
654+ { showDefaultFlavor && (
632655 < div className = "error__flavor" >
633656 Beep boop. Server something error happens.
634657 </ div >
@@ -637,6 +660,26 @@ export function ErrorBoundary() {
637660 ) ;
638661}
639662
663+ function dedupeDescription (
664+ headline : string ,
665+ description : string | undefined
666+ ) : string | undefined {
667+ if ( ! description ) {
668+ return undefined ;
669+ }
670+
671+ const trimmedDescription = description . trim ( ) ;
672+ if ( ! trimmedDescription ) {
673+ return undefined ;
674+ }
675+
676+ if ( trimmedDescription . toLowerCase ( ) === headline . trim ( ) . toLowerCase ( ) ) {
677+ return undefined ;
678+ }
679+
680+ return trimmedDescription ;
681+ }
682+
640683// Temporary solution for implementing ads
641684// REMIX TODO: Move to dynamic html
642685function AdsInit ( ) {
@@ -735,7 +778,10 @@ function getCommunityBreadcrumb(
735778 </ span >
736779 }
737780 >
738- < Await resolve = { communityPage . data . community } >
781+ < Await
782+ resolve = { communityPage . data . community }
783+ errorElement = { < NimbusAwaitErrorElement /> }
784+ >
739785 { ( resolvedValue ) => {
740786 let label = undefined ;
741787 let icon = undefined ;
0 commit comments