|
1 | 1 | import * as Common from "@frontend/common"; |
2 | 2 | import { CircularProgress, Stack, Theme } from "@mui/material"; |
3 | 3 | import { ErrorBoundary, Suspense } from "@suspensive/react"; |
| 4 | +import { useQueryClient } from "@tanstack/react-query"; |
4 | 5 | import { AxiosError, AxiosResponse } from "axios"; |
5 | 6 | import * as React from "react"; |
6 | | -import { useLocation, useParams } from "react-router-dom"; |
| 7 | +import { useParams } from "react-router-dom"; |
7 | 8 | import * as R from "remeda"; |
8 | 9 |
|
9 | 10 | import { useAppContext } from "../../contexts/app_context"; |
@@ -86,46 +87,55 @@ const RouteErrorFallback: React.FC<{ error: Error; reset: () => void }> = ({ err |
86 | 87 | return <Common.Components.ErrorFallback error={error} reset={reset} />; |
87 | 88 | }; |
88 | 89 |
|
89 | | -export const PageRenderer: React.FC<{ id: string }> = ErrorBoundary.with( |
90 | | - { fallback: RouteErrorFallback }, |
91 | | - Suspense.with({ fallback: <CenteredLoadingPage /> }, ({ id }) => { |
92 | | - const { setAppContext } = useAppContext(); |
93 | | - const backendClient = Common.Hooks.BackendAPI.useBackendClient(); |
94 | | - const { data } = Common.Hooks.BackendAPI.usePageQuery(backendClient, id); |
95 | | - |
96 | | - React.useEffect(() => { |
97 | | - setAppContext((prev) => ({ |
98 | | - ...prev, |
99 | | - title: data.title, |
100 | | - shouldShowTitleBanner: data.show_top_title_banner, |
101 | | - shouldShowSponsorBanner: data.show_bottom_sponsor_banner, |
102 | | - })); |
103 | | - }, [data, setAppContext]); |
104 | | - |
105 | | - return ( |
106 | | - <Stack sx={initialPageStyle(Common.Utils.parseCss(data.css))}> |
107 | | - {data.sections.map((s) => ( |
108 | | - <Stack sx={initialSectionStyle(Common.Utils.parseCss(s.css))} key={s.id}> |
109 | | - <Common.Components.MDXRenderer text={s.body} /> |
110 | | - </Stack> |
111 | | - ))} |
112 | | - </Stack> |
113 | | - ); |
114 | | - }) |
| 90 | +const WaitedCenteredLoadingPage: React.FC = Suspense.with({ fallback: <CenteredLoadingPage /> }, () => { |
| 91 | + const [isFetching, setIsFetching] = React.useState(true); |
| 92 | + const qClient = useQueryClient(); |
| 93 | + |
| 94 | + React.useEffect(() => { |
| 95 | + const unsubscribe = qClient.getQueryCache().subscribe(() => setIsFetching(qClient.isFetching() > 0)); |
| 96 | + return () => unsubscribe(); |
| 97 | + }, [qClient]); |
| 98 | + |
| 99 | + return isFetching ? <CenteredLoadingPage /> : <PageNotFound />; |
| 100 | +}); |
| 101 | + |
| 102 | +const InnerPageRenderer: React.FC<{ id: string }> = Suspense.with({ fallback: <CenteredLoadingPage /> }, ({ id }) => { |
| 103 | + const { setAppContext } = useAppContext(); |
| 104 | + const backendClient = Common.Hooks.BackendAPI.useBackendClient(); |
| 105 | + const { data } = Common.Hooks.BackendAPI.usePageQuery(backendClient, id); |
| 106 | + |
| 107 | + React.useEffect(() => { |
| 108 | + setAppContext((prev) => ({ |
| 109 | + ...prev, |
| 110 | + title: data.title, |
| 111 | + shouldShowTitleBanner: data.show_top_title_banner, |
| 112 | + shouldShowSponsorBanner: data.show_bottom_sponsor_banner, |
| 113 | + })); |
| 114 | + }, [data, setAppContext]); |
| 115 | + |
| 116 | + return ( |
| 117 | + <Stack sx={initialPageStyle(Common.Utils.parseCss(data.css))}> |
| 118 | + {data.sections.map((s) => ( |
| 119 | + <Stack sx={initialSectionStyle(Common.Utils.parseCss(s.css))} key={s.id}> |
| 120 | + <Common.Components.MDXRenderer text={s.body} /> |
| 121 | + </Stack> |
| 122 | + ))} |
| 123 | + </Stack> |
| 124 | + ); |
| 125 | +}); |
| 126 | + |
| 127 | +export const PageRenderer: React.FC<{ id: string }> = ({ id }) => ( |
| 128 | + <ErrorBoundary fallback={RouteErrorFallback} resetKeys={[id]}> |
| 129 | + <InnerPageRenderer id={id} /> |
| 130 | + </ErrorBoundary> |
115 | 131 | ); |
116 | 132 |
|
117 | 133 | export const RouteRenderer: React.FC = ErrorBoundary.with( |
118 | 134 | { fallback: RouteErrorFallback }, |
119 | 135 | Suspense.with({ fallback: <CenteredLoadingPage /> }, () => { |
120 | | - const location = useLocation(); |
121 | 136 | const { siteMapNode, currentSiteMapDepth } = useAppContext(); |
122 | | - |
123 | | - if (!siteMapNode) return <CenteredLoadingPage />; |
124 | | - |
125 | 137 | const routeInfo = !R.isEmpty(currentSiteMapDepth) && currentSiteMapDepth[currentSiteMapDepth.length - 1]; |
126 | | - if (!routeInfo) throwPageNotFound(`Route ${location} not found`); |
127 | | - |
128 | | - return <PageRenderer id={routeInfo.page} />; |
| 138 | + return !(siteMapNode && routeInfo) ? <WaitedCenteredLoadingPage /> : <PageRenderer id={routeInfo.page} />; |
129 | 139 | }) |
130 | 140 | ); |
131 | 141 |
|
|
0 commit comments