diff --git a/apps/rr7/app/content.tsx b/apps/rr7/app/content.tsx
index a8483813d9..cfc6134824 100644
--- a/apps/rr7/app/content.tsx
+++ b/apps/rr7/app/content.tsx
@@ -1,39 +1,20 @@
-import type { LoaderArgs } from './routes/+types.home';
-import {
- dehydrate,
- QueryClient,
- HydrationBoundary,
- useQuery,
- useQueryClient,
-} from '@tanstack/react-query';
-import { useLoaderData, useLocation } from 'react-router';
-import type { MetaFunction } from 'react-router';
-import { usePloneClient } from '@plone/providers';
+import type { Route } from './+types/content';
+import { data, useLoaderData, useLocation } from 'react-router';
import PloneClient from '@plone/client';
import App from '@plone/slots/components/App';
import config from '@plone/registry';
-export const meta: MetaFunction = () => {
+export const meta: Route.MetaFunction = ({ data }) => {
return [
- { title: 'Plone on React Router 7' },
- { name: 'description', content: 'Welcome to Plone!' },
+ { title: data?.title },
+ { name: 'description', content: data?.description },
];
};
const expand = ['navroot', 'breadcrumbs', 'navigation'];
// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export async function loader({ params, request }: LoaderArgs) {
- const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- // With SSR, we usually want to set some default staleTime
- // above 0 to avoid refetching immediately on the client
- staleTime: 60 * 1000,
- },
- },
- });
-
+export async function loader({ params, request }: Route.LoaderArgs) {
const ploneClient = config
.getUtility({
name: 'ploneClient',
@@ -41,7 +22,7 @@ export async function loader({ params, request }: LoaderArgs) {
})
.method();
- const { getContentQuery } = ploneClient as PloneClient;
+ const { getContent } = ploneClient as PloneClient;
const path = new URL(request.url).pathname;
@@ -57,30 +38,20 @@ export async function loader({ params, request }: LoaderArgs) {
)
) {
console.log('prefetching', path);
- await queryClient.prefetchQuery(getContentQuery({ path, expand }));
+ try {
+ return await getContent({ path, expand });
+ } catch (error) {
+ throw data('Content Not Found', { status: 404 });
+ }
} else {
console.log('path not prefetched', path);
+ throw data('Content Not Found', { status: 404 });
}
-
- return { dehydratedState: dehydrate(queryClient) };
-}
-
-function Page() {
- const { getContentQuery } = usePloneClient();
- const pathname = useLocation().pathname;
- const { data } = useQuery(getContentQuery({ path: pathname, expand }));
-
- if (!data) return 'Loading...';
- return ;
}
export default function Content() {
- const { dehydratedState } = useLoaderData();
- const queryClient = useQueryClient();
+ const data = useLoaderData();
+ const pathname = useLocation().pathname;
- return (
-
-
-
- );
+ return ;
}
diff --git a/apps/rr7/app/root.tsx b/apps/rr7/app/root.tsx
index d1c4bb5bae..7340c7627a 100644
--- a/apps/rr7/app/root.tsx
+++ b/apps/rr7/app/root.tsx
@@ -1,3 +1,5 @@
+import type { LinksFunction } from 'react-router';
+import type { Route } from './+types/root';
import { useState } from 'react';
import {
Links,
@@ -10,8 +12,8 @@ import {
useNavigate as useRRNavigate,
useParams,
useLoaderData,
+ isRouteErrorResponse,
} from 'react-router';
-import type { LinksFunction } from 'react-router';
import { QueryClient } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
@@ -24,8 +26,8 @@ import installSSR from './config.server';
install();
-import '@plone/theming/styles/main.css';
-import '@plone/slots/main.css';
+import themingMain from '@plone/theming/styles/main.css?url';
+import slotsMain from '@plone/slots/main.css?url';
function useNavigate() {
const navigate = useRRNavigate();
@@ -37,6 +39,8 @@ function useHrefLocal(to: string) {
}
export const links: LinksFunction = () => [
+ { rel: 'stylesheet', href: themingMain },
+ { rel: 'stylesheet', href: slotsMain },
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
{
rel: 'preconnect',
@@ -85,6 +89,34 @@ export function Layout({ children }: { children: React.ReactNode }) {
);
}
+export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
+ let message = 'Oops!';
+ let details = 'An unexpected error occurred.';
+ let stack: string | undefined;
+ if (isRouteErrorResponse(error)) {
+ message = error.status === 404 ? '404' : 'Error';
+ details =
+ error.status === 404
+ ? 'The requested page could not be found.'
+ : error.statusText || details;
+ } else if (import.meta.env.DEV && error && error instanceof Error) {
+ details = error.message;
+ stack = error.stack;
+ }
+
+ return (
+
+ {message}
+ {details}
+ {stack && (
+
+ {stack}
+
+ )}
+
+ );
+}
+
export default function App() {
if (!import.meta.env.SSR) {
config.settings.apiPath = window.env.PLONE_API_PATH;
diff --git a/apps/rr7/app/routes.ts b/apps/rr7/app/routes.ts
index a4981be3dc..4d6b9ec32f 100644
--- a/apps/rr7/app/routes.ts
+++ b/apps/rr7/app/routes.ts
@@ -4,7 +4,7 @@ import { index, route } from '@react-router/dev/routes';
const routes: RouteConfig = [
index('content.tsx', { id: 'index' }),
route('ok', 'okroute.tsx', { id: 'ok' }),
- route('*', 'content.tsx', { id: 'splat' }),
+ route('*', 'content.tsx', { id: 'content' }),
];
export default routes;
diff --git a/packages/client/news/6594.feature b/packages/client/news/6594.feature
new file mode 100644
index 0000000000..7ba9fa94c3
--- /dev/null
+++ b/packages/client/news/6594.feature
@@ -0,0 +1 @@
+Import `getContent` bare fetcher. @sneridagh
diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts
index b0d5e5289a..a14033d7f2 100644
--- a/packages/client/src/client.ts
+++ b/packages/client/src/client.ts
@@ -4,6 +4,7 @@ import {
} from './restapi/login/post';
import type { LoginArgs } from './restapi/login/post';
+import { getContent as _getContent } from './restapi/content/get';
import { getContentQuery as _getContentQuery } from './restapi/content/get';
import { createContentMutation as _createContentMutation } from './restapi/content/add';
import { updateContentMutation as _updateContentMutation } from './restapi/content/update';
@@ -150,6 +151,7 @@ export default class PloneClient {
/*
Content queries
*/
+ getContent = queryWithConfig(_getContent, this.getConfig);
getContentQuery = queryWithConfig(_getContentQuery, this.getConfig);
createContentMutation = mutationWithConfig(
_createContentMutation,