diff --git a/common/koa-middleware/withCachedValues.ts b/common/koa-middleware/withCachedValues.ts index e6761ef44d..a515f3e88e 100644 --- a/common/koa-middleware/withCachedValues.ts +++ b/common/koa-middleware/withCachedValues.ts @@ -1,8 +1,12 @@ +import compose from 'koa-compose'; +import { withPrismicPreviewStatus } from './withPrismicPreviewStatus'; import { IncomingMessage, ServerResponse } from 'http'; import Router from 'koa-router'; import { NextServer } from 'next/dist/server/next'; import { parse, UrlWithParsedQuery } from 'url'; // eslint-disable-line n/no-deprecated-api +export const withCachedValues = compose([withPrismicPreviewStatus]); + export async function route( path: string, page: string, diff --git a/common/koa-middleware/withPrismicPreviewStatus.ts b/common/koa-middleware/withPrismicPreviewStatus.ts new file mode 100644 index 0000000000..b726cbfb41 --- /dev/null +++ b/common/koa-middleware/withPrismicPreviewStatus.ts @@ -0,0 +1,27 @@ +import Koa from 'koa'; + +export function withPrismicPreviewStatus( + ctx: Koa.DefaultContext, + next: Koa.Next + /* eslint-disable @typescript-eslint/no-explicit-any */ +): Promise { + /* eslint-enable @typescript-eslint/no-explicit-any */ + + // for previews on localhost we use /preview to determine whether the 'isPreview' cookie should be set + // this kinda works for live too, but not for shared preview links, as they never hit /preview + // we therefore look for the subdomain .preview to determine if it's a preview + const previewCookieName = 'isPreview'; + const isPreviewDomain = Boolean(ctx.request.host.startsWith('preview.')); + const previewCookieMatch = ctx.headers.cookie + ? ctx.headers.cookie.match(`(^|;) ?${previewCookieName}=([^;]*)(;|$)`) + : undefined; + + const previewCookie = previewCookieMatch ? previewCookieMatch[2] : undefined; + + if (isPreviewDomain && !previewCookie) { + ctx.cookies.set('isPreview', 'true', { + httpOnly: false, + }); + } + return next(); +} diff --git a/common/views/components/CivicUK/index.tsx b/common/views/components/CivicUK/index.tsx index b5c4ab7264..02762d6840 100644 --- a/common/views/components/CivicUK/index.tsx +++ b/common/views/components/CivicUK/index.tsx @@ -65,7 +65,7 @@ const necessaryCookies = () => { const wcCookies = Object.values(cookies).map(c => c); // Allows Prismic previews - const prismicPreview = ['io.prismic.preview']; + const prismicPreview = ['io.prismic.preview', 'isPreview']; // See @weco/toggles/webapp/toggles for details on each const featureFlags = ['toggle_*']; diff --git a/common/views/pages/_app.tsx b/common/views/pages/_app.tsx index de486265d5..2540f074fd 100644 --- a/common/views/pages/_app.tsx +++ b/common/views/pages/_app.tsx @@ -2,7 +2,6 @@ import { NextPage } from 'next'; import { AppProps } from 'next/app'; import React, { useEffect, FunctionComponent, ReactElement } from 'react'; import { ThemeProvider } from 'styled-components'; -import { PrismicPreview } from '@prismicio/next'; import theme, { GlobalStyle } from '@weco/common/views/themes/default'; import LoadingIndicator from '@weco/common/views/components/LoadingIndicator/LoadingIndicator'; import { AppContextProvider } from '@weco/common/views/components/AppContext/AppContext'; @@ -21,6 +20,7 @@ import { ServerDataContext } from '@weco/common/server-data/Context'; import UserProvider from '@weco/common/views/components/UserProvider/UserProvider'; import { ApmContextProvider } from '@weco/common/views/components/ApmContext/ApmContext'; import { AppErrorProps } from '@weco/common/services/app'; +import usePrismicPreview from '@weco/common/services/app/usePrismicPreview'; import useMaintainPageHeight from '@weco/common/services/app/useMaintainPageHeight'; import { GaDimensions } from '@weco/common/services/app/google-analytics'; import { deserialiseProps } from '@weco/common/utils/json'; @@ -129,6 +129,8 @@ const WecoApp: FunctionComponent = ({ // or when requested client-side through next/link or next/router // i.e. everything that we consider to be a page view + usePrismicPreview(() => Boolean(document.cookie.match('isPreview=true'))); + const getLayout = Component.getLayout || (page => <>{page}); return ( @@ -158,8 +160,6 @@ const WecoApp: FunctionComponent = ({ title={pageProps.err.message} /> )} - - diff --git a/content/webapp/app.ts b/content/webapp/app.ts index dabf12a674..ca7da7fff1 100644 --- a/content/webapp/app.ts +++ b/content/webapp/app.ts @@ -6,7 +6,10 @@ import Router from 'koa-router'; import next from 'next'; import { apmErrorMiddleware } from '@weco/common/services/apm/errorMiddleware'; import { init as initServerData } from '@weco/common/server-data'; -import { handleAllRoute } from '@weco/common/koa-middleware/withCachedValues'; +import { + withCachedValues, + handleAllRoute, +} from '@weco/common/koa-middleware/withCachedValues'; import linkResolver from '@weco/common/services/prismic/link-resolver'; import { createClient as createPrismicClient } from '@weco/common/services/prismic/fetch'; import * as prismic from '@prismicio/client'; @@ -41,6 +44,7 @@ const appPromise = nextApp }); koaApp.use(apmErrorMiddleware); + koaApp.use(withCachedValues); // Add a naive healthcheck endpoint for the load balancer router.get('/management/healthcheck', async ctx => { @@ -68,6 +72,10 @@ const appPromise = nextApp defaultURL: '/', }); + ctx.cookies.set('isPreview', 'true', { + httpOnly: false, + }); + ctx.redirect(url); });