99 Await ,
1010 type LoaderFunctionArgs ,
1111 Outlet ,
12+ useLoaderData ,
1213 useOutletContext ,
1314} from "react-router" ;
1415import { useLoaderData } from "react-router" ;
@@ -17,79 +18,96 @@ import { type OutletContextShape } from "~/root";
1718import { NewButton , NewIcon , SkeletonBox } from "@thunderstore/cyberstorm" ;
1819import { DapperTs } from "@thunderstore/dapper-ts" ;
1920import { getPackageWiki } from "@thunderstore/dapper-ts/src/methods/package" ;
21+ import { NewButton , NewIcon , SkeletonBox } from "@thunderstore/cyberstorm" ;
22+ import { faPlus } from "@fortawesome/pro-solid-svg-icons" ;
23+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
24+ import { type OutletContextShape } from "~/root" ;
25+ import { Suspense } from "react" ;
26+ import { handleLoaderError } from "cyberstorm/utils/errors/handleLoaderError" ;
27+ import { createNotFoundMapping } from "cyberstorm/utils/errors/loaderMappings" ;
28+ import {
29+ NimbusAwaitErrorElement ,
30+ NimbusDefaultRouteErrorBoundary ,
31+ } from "cyberstorm/utils/errors/NimbusErrorBoundary" ;
32+ import { throwUserFacingPayloadResponse } from "cyberstorm/utils/errors/userFacingErrorResponse" ;
33+ import { getLoaderTools } from "cyberstorm/utils/getLoaderTools" ;
34+
35+ export const wikiErrorMappings = [
36+ createNotFoundMapping (
37+ "Wiki not available." ,
38+ "We could not find the requested wiki."
39+ ) ,
40+ ] ;
2041
2142import { ApiError } from "../../../../../../packages/thunderstore-api/src" ;
2243import "./Wiki.css" ;
2344
2445export async function loader ( { params } : LoaderFunctionArgs ) {
2546 if ( params . communityId && params . namespaceId && params . packageId ) {
26- const publicEnvVariables = getPublicEnvVariables ( [ "VITE_API_URL" ] ) ;
27- const dapper = new DapperTs ( ( ) => {
47+ const { dapper } = getLoaderTools ( ) ;
48+ try {
49+ const wiki = await dapper . getPackageWiki (
50+ params . namespaceId ,
51+ params . packageId
52+ ) ;
53+
2854 return {
29- apiHost : publicEnvVariables . VITE_API_URL ,
30- sessionId : undefined ,
55+ wiki,
56+ communityId : params . communityId ,
57+ namespaceId : params . namespaceId ,
58+ packageId : params . packageId ,
59+ slug : params . slug ,
60+ permissions : undefined ,
3161 } ;
32- } ) ;
33-
34- let wiki : Awaited < ReturnType < typeof getPackageWiki > > | undefined ;
35-
36- try {
37- wiki = await dapper . getPackageWiki ( params . namespaceId , params . packageId ) ;
3862 } 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- }
63+ handleLoaderError ( error , { mappings : wikiErrorMappings } ) ;
4764 }
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- } ;
5765 } else {
58- throw new Error ( "Namespace ID or Package ID is missing" ) ;
66+ throwUserFacingPayloadResponse ( {
67+ headline : "Wiki not available." ,
68+ description : "We could not find the requested wiki." ,
69+ category : "not_found" ,
70+ status : 404 ,
71+ } ) ;
5972 }
6073}
6174
6275export async function clientLoader ( { params } : LoaderFunctionArgs ) {
6376 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- } ) ;
77+ const { dapper } = getLoaderTools ( ) ;
7178
72- const wiki = dapper . getPackageWiki ( params . namespaceId , params . packageId ) ;
79+ const wikiPromise = dapper . getPackageWiki (
80+ params . namespaceId ,
81+ params . packageId
82+ ) ;
7383
74- const permissions = dapper . getPackagePermissions (
84+ const permissionsPromise = dapper . getPackagePermissions (
7585 params . communityId ,
7686 params . namespaceId ,
7787 params . packageId
7888 ) ;
7989
8090 return {
81- wiki : wiki ,
91+ wiki : wikiPromise ,
8292 communityId : params . communityId ,
8393 namespaceId : params . namespaceId ,
8494 packageId : params . packageId ,
8595 slug : params . slug ,
86- permissions : permissions ,
96+ permissions : permissionsPromise ,
8797 } ;
8898 } else {
89- throw new Error ( "Namespace ID or Package ID is missing" ) ;
99+ throwUserFacingPayloadResponse ( {
100+ headline : "Wiki not available." ,
101+ description : "We could not find the requested wiki." ,
102+ category : "not_found" ,
103+ status : 404 ,
104+ } ) ;
90105 }
91106}
92107
108+ /**
109+ * Displays the package wiki navigation and nested routes, relying on Suspense for data.
110+ */
93111export default function Wiki ( ) {
94112 const { wiki, communityId, namespaceId, packageId, slug, permissions } =
95113 useLoaderData < typeof loader | typeof clientLoader > ( ) ;
@@ -100,7 +118,10 @@ export default function Wiki() {
100118 < div className = "package-wiki" >
101119 < div className = "package-wiki-nav" >
102120 < Suspense >
103- < Await resolve = { permissions } >
121+ < Await
122+ resolve = { permissions }
123+ errorElement = { < NimbusAwaitErrorElement /> }
124+ >
104125 { ( resolvedValue ) =>
105126 resolvedValue ?. permissions . can_manage ? (
106127 < div className = "package-wiki-nav__header" >
@@ -126,7 +147,7 @@ export default function Wiki() {
126147 < Suspense
127148 fallback = { < SkeletonBox className = "package-wiki-nav__skeleton" /> }
128149 >
129- < Await resolve = { wiki } errorElement = { < > < /> } >
150+ < Await resolve = { wiki } errorElement = { < NimbusAwaitErrorElement /> } >
130151 { ( resolvedValue ) =>
131152 resolvedValue &&
132153 resolvedValue . pages . map ( ( page , index ) => {
@@ -194,3 +215,7 @@ export default function Wiki() {
194215 </ div >
195216 ) ;
196217}
218+
219+ export function ErrorBoundary ( ) {
220+ return < NimbusDefaultRouteErrorBoundary /> ;
221+ }
0 commit comments