Skip to content

Commit

Permalink
feat: add PreviewIndicator component
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasio committed Jul 3, 2024
1 parent 8b2858b commit d7cc96f
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 13 deletions.
6 changes: 3 additions & 3 deletions packages/next/src/handlers/previewHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type PreviewHandlerOptions = {
*
* If set you should handle the redirect yourself by calling `res.redirect`.
*
* **Important**: You should not need to override this but if you do, uou must append `-preview=true` to the end of the redirected url.
* **Important**: You should not need to override this but if you do, you must append `-preview=true` to the end of the redirected url.
*
* This can be used to customize the preview url.
*
Expand Down Expand Up @@ -55,7 +55,7 @@ export type PreviewHandlerOptions = {
/**
* If passed will override the default redirect path
*
* **Important**: You should not need to override this but if you do, uou must append `-preview=true` to the end of the redirecte path.
* **Important**: You should not need to override this but if you do, you must append `-preview=true` to the end of the redirecte path.
*
* @param defaultRedirectPath the default redirect path
* @param post PostEntity
Expand Down Expand Up @@ -235,7 +235,7 @@ export async function previewHandler(

res.setPreviewData(previewData, {
maxAge: 5 * 60,
// we can only safely narrow the cookei to a path if getRedirectPath is implemented or
// we can only safely narrow the cookie to a path if getRedirectPath is implemented or
// it's using the default behavior without a custom onRedirect
path: shouldSetPathInCookie ? redirectPath : '/',
});
Expand Down
10 changes: 6 additions & 4 deletions packages/next/src/middlewares/appMidleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export async function AppMiddleware(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options: AppMidlewareOptions = { appRouter: false },
) {
const response = NextResponse.next();
let response = NextResponse.next();

if (isStaticAssetRequest(req) || isInternalRequest(req)) {
return response;
Expand Down Expand Up @@ -53,13 +53,15 @@ export async function AppMiddleware(

if (isMultisiteRequest) {
const hostname = req.headers.get('host') || '';
response.headers.set('x-headstartwp-site', hostname);
const url = req.nextUrl;

const url = req.nextUrl;
url.pathname = `/_sites/${hostname}${url.pathname}`;

return NextResponse.rewrite(url);
response = NextResponse.rewrite(url);
response.headers.set('x-headstartwp-site', hostname);
}

response.headers.set('x-headstartwp-current-url', req.nextUrl.pathname);

return response;
}
28 changes: 28 additions & 0 deletions packages/next/src/rsc/components/PreviewIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { cookies, draftMode, headers } from 'next/headers';
import React from 'react';
import { redirect } from 'next/navigation';
import { COOKIE_NAME } from '../handlers/previewRouteHandler';

export const PreviewIndicator: React.FC = () => {
const { isEnabled } = draftMode();

if (!isEnabled) {
return null;
}

async function disableDraftMode() {
'use server';

const currentUrl = headers().get('x-headstartwp-current-url') ?? '/';
draftMode().disable();
cookies().delete(COOKIE_NAME);
redirect(currentUrl);
}

return (
<form action={disableDraftMode}>
You are previewing the current page.
<button type="submit">Exit Preview</button>
</form>
);
};
83 changes: 78 additions & 5 deletions packages/next/src/rsc/handlers/previewRouteHandler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {
CustomPostType,
PostEntity,
fetchPost,
getCustomPostType,
getHeadstartWPConfig,
Expand All @@ -12,7 +14,49 @@ import type { PreviewData } from '../../handlers';

export const COOKIE_NAME = 'headstartwp_preview';

export async function previewRouteHandler(request: NextRequest) {
/**
* The options supported by {@link previewRouteHandler}
*/
export type PreviewRouteHandlerOptions = {
/**
* If passed will override the default redirect path
*
* @returns the new redirect path
*/
getRedirectPath?: (options: {
req: NextRequest;
defaultRedirectPath: string;
post: PostEntity;
postTypeDef: CustomPostType;
previewData: PreviewData;
}) => string;

/**
* If passed, this function will be called when the preview data is fetched and allows
* for additional preview data to be set.
*
* The preview data is serialized and stored in a cookie.
*/
preparePreviewData?: (options: {
req: NextRequest;
post: PostEntity;
postTypeDef: CustomPostType;
previewData: PreviewData;
}) => PreviewData;

onRedirect?: (options: {
req: NextRequest;
redirectpath?: string;
previewData: PreviewData;
postTypeDef: CustomPostType;
post: PostEntity;
}) => void;
};

export async function previewRouteHandler(
request: NextRequest,
options: PreviewRouteHandlerOptions = {},
) {
const { searchParams } = request.nextUrl;
const post_id = Number(searchParams.get('post_id') ?? 0);
const post_type = searchParams.get('post_type');
Expand All @@ -35,7 +79,7 @@ export async function previewRouteHandler(request: NextRequest) {

const revision = is_revision === '1';

const postTypeDef = getCustomPostType(post_type as string, sourceUrl);
const postTypeDef = getCustomPostType(post_type, sourceUrl);

if (!postTypeDef) {
return new Response(
Expand Down Expand Up @@ -68,13 +112,23 @@ export async function previewRouteHandler(request: NextRequest) {
if (result?.id === id || result?.parent === id) {
const { slug } = result;

const previewData: PreviewData = {
let previewData: PreviewData = {
id,
postType: post_type as string,
revision,
authToken: token as string,
};

previewData =
typeof options.preparePreviewData === 'function'
? options.preparePreviewData({
req: request,
post: result,
previewData,
postTypeDef,
})
: previewData;

/**
* Builds the default redirect path
*
Expand Down Expand Up @@ -102,7 +156,17 @@ export async function previewRouteHandler(request: NextRequest) {
return `/${path}`;
};

const redirectPath = getDefaultRedirectPath();
const defaultRedirectPath = getDefaultRedirectPath();
const redirectPath =
typeof options.getRedirectPath === 'function'
? options.getRedirectPath({
req: request,
defaultRedirectPath,
post: result,
postTypeDef,
previewData,
})
: defaultRedirectPath;

cookies().set(COOKIE_NAME, JSON.stringify(previewData), {
maxAge: 5 * 60,
Expand All @@ -113,7 +177,16 @@ export async function previewRouteHandler(request: NextRequest) {

draftMode().enable();

redirect(redirectPath);
if (typeof options.onRedirect === 'function') {
options.onRedirect({
req: request,
previewData,
postTypeDef,
post: result,
});
} else {
redirect(redirectPath);
}
}

return new Response('There was an error setting up preview', { status: 500 });
Expand Down
3 changes: 3 additions & 0 deletions packages/next/src/rsc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ export * from './config';

// handlers
export * from './handlers/previewRouteHandler';

// components
export * from './components/PreviewIndicator';
6 changes: 5 additions & 1 deletion projects/wp-nextjs-app/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
import { PreviewIndicator } from '@headstartwp/next/app';

const inter = Inter({ subsets: ['latin'] });

Expand All @@ -16,7 +17,10 @@ const RootLayout = ({
}>) => {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<body className={inter.className}>
{children}
<PreviewIndicator />
</body>
</html>
);
};
Expand Down
File renamed without changes.

0 comments on commit d7cc96f

Please sign in to comment.