11import { faPlus } from "@fortawesome/pro-solid-svg-icons" ;
22import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
33import {
4- getPublicEnvVariables ,
5- getSessionTools ,
6- } from "cyberstorm/security/publicEnvVariables" ;
4+ NimbusAwaitErrorElement ,
5+ NimbusDefaultRouteErrorBoundary ,
6+ } from "cyberstorm/utils/errors/NimbusErrorBoundary" ;
7+ import { handleLoaderError } from "cyberstorm/utils/errors/handleLoaderError" ;
8+ import { createNotFoundMapping } from "cyberstorm/utils/errors/loaderMappings" ;
9+ import { throwUserFacingPayloadResponse } from "cyberstorm/utils/errors/userFacingErrorResponse" ;
10+ import { getLoaderTools } from "cyberstorm/utils/getLoaderTools" ;
711import { Suspense } from "react" ;
812import {
913 Await ,
1014 type LoaderFunctionArgs ,
1115 Outlet ,
16+ useLoaderData ,
1217 useOutletContext ,
1318} from "react-router" ;
14- import { useLoaderData } from "react-router" ;
1519import { type OutletContextShape } from "~/root" ;
1620
1721import { NewButton , NewIcon , SkeletonBox } from "@thunderstore/cyberstorm" ;
18- import { DapperTs } from "@thunderstore/dapper-ts" ;
19- import { getPackageWiki } from "@thunderstore/dapper-ts" ;
20- import { ApiError } from "@thunderstore/thunderstore-api" ;
2122
2223import "./Wiki.css" ;
2324
25+ export const wikiErrorMappings = [
26+ createNotFoundMapping (
27+ "Wiki not available." ,
28+ "We could not find the requested wiki."
29+ ) ,
30+ ] ;
31+
2432export async function loader ( { params } : LoaderFunctionArgs ) {
2533 if ( params . communityId && params . namespaceId && params . packageId ) {
26- const publicEnvVariables = getPublicEnvVariables ( [ "VITE_API_URL" ] ) ;
27- const dapper = new DapperTs ( ( ) => {
34+ const { dapper } = getLoaderTools ( ) ;
35+ try {
36+ const wiki = await dapper . getPackageWiki (
37+ params . namespaceId ,
38+ params . packageId
39+ ) ;
40+
2841 return {
29- apiHost : publicEnvVariables . VITE_API_URL ,
30- sessionId : undefined ,
42+ wiki,
43+ communityId : params . communityId ,
44+ namespaceId : params . namespaceId ,
45+ packageId : params . packageId ,
46+ slug : params . slug ,
47+ permissions : undefined ,
3148 } ;
32- } ) ;
33-
34- let wiki : Awaited < ReturnType < typeof getPackageWiki > > | undefined ;
35-
36- try {
37- wiki = await dapper . getPackageWiki ( params . namespaceId , params . packageId ) ;
3849 } catch ( error ) {
39- if ( error instanceof ApiError ) {
40- if ( error . response . status === 404 ) {
41- wiki = undefined ;
42- } else {
43- wiki = undefined ;
44- console . error ( "Error fetching package wiki:" , error ) ;
45- }
46- }
50+ handleLoaderError ( error , { mappings : wikiErrorMappings } ) ;
4751 }
48-
49- return {
50- wiki : wiki ,
51- communityId : params . communityId ,
52- namespaceId : params . namespaceId ,
53- packageId : params . packageId ,
54- slug : params . slug ,
55- permissions : undefined ,
56- } ;
5752 } else {
58- throw new Error ( "Namespace ID or Package ID is missing" ) ;
53+ throwUserFacingPayloadResponse ( {
54+ headline : "Wiki not available." ,
55+ description : "We could not find the requested wiki." ,
56+ category : "not_found" ,
57+ status : 404 ,
58+ } ) ;
5959 }
6060}
6161
6262export async function clientLoader ( { params } : LoaderFunctionArgs ) {
6363 if ( params . communityId && params . namespaceId && params . packageId ) {
64- const tools = getSessionTools ( ) ;
65- const dapper = new DapperTs ( ( ) => {
66- return {
67- apiHost : tools ?. getConfig ( ) . apiHost ,
68- sessionId : tools ?. getConfig ( ) . sessionId ,
69- } ;
70- } ) ;
64+ const { dapper } = getLoaderTools ( ) ;
7165
72- const wiki = dapper . getPackageWiki ( params . namespaceId , params . packageId ) ;
66+ const wikiPromise = dapper . getPackageWiki (
67+ params . namespaceId ,
68+ params . packageId
69+ ) ;
7370
74- const permissions = dapper . getPackagePermissions (
71+ const permissionsPromise = dapper . getPackagePermissions (
7572 params . communityId ,
7673 params . namespaceId ,
7774 params . packageId
7875 ) ;
7976
8077 return {
81- wiki : wiki ,
78+ wiki : wikiPromise ,
8279 communityId : params . communityId ,
8380 namespaceId : params . namespaceId ,
8481 packageId : params . packageId ,
8582 slug : params . slug ,
86- permissions : permissions ,
83+ permissions : permissionsPromise ,
8784 } ;
8885 } else {
89- throw new Error ( "Namespace ID or Package ID is missing" ) ;
86+ throwUserFacingPayloadResponse ( {
87+ headline : "Wiki not available." ,
88+ description : "We could not find the requested wiki." ,
89+ category : "not_found" ,
90+ status : 404 ,
91+ } ) ;
9092 }
9193}
9294
95+ /**
96+ * Displays the package wiki navigation and nested routes, relying on Suspense for data.
97+ */
9398export default function Wiki ( ) {
9499 const { wiki, communityId, namespaceId, packageId, slug, permissions } =
95100 useLoaderData < typeof loader | typeof clientLoader > ( ) ;
@@ -100,7 +105,10 @@ export default function Wiki() {
100105 < div className = "package-wiki" >
101106 < div className = "package-wiki-nav" >
102107 < Suspense >
103- < Await resolve = { permissions } >
108+ < Await
109+ resolve = { permissions }
110+ errorElement = { < NimbusAwaitErrorElement /> }
111+ >
104112 { ( resolvedValue ) =>
105113 resolvedValue ?. permissions . can_manage ? (
106114 < div className = "package-wiki-nav__header" >
@@ -126,7 +134,7 @@ export default function Wiki() {
126134 < Suspense
127135 fallback = { < SkeletonBox className = "package-wiki-nav__skeleton" /> }
128136 >
129- < Await resolve = { wiki } errorElement = { < > < /> } >
137+ < Await resolve = { wiki } errorElement = { < NimbusAwaitErrorElement /> } >
130138 { ( resolvedValue ) =>
131139 resolvedValue &&
132140 resolvedValue . pages . map ( ( page , index ) => {
@@ -194,3 +202,7 @@ export default function Wiki() {
194202 </ div >
195203 ) ;
196204}
205+
206+ export function ErrorBoundary ( ) {
207+ return < NimbusDefaultRouteErrorBoundary /> ;
208+ }
0 commit comments