feat(SW-508): preview for content pages

This commit is contained in:
Erik Tiekstra
2024-10-25 11:28:55 +02:00
parent 18eeeef510
commit bc93fcaefd
8 changed files with 108 additions and 66 deletions

View File

@@ -1,26 +1,29 @@
import InitLivePreview from "@/components/Current/LivePreview" import "@/app/globals.css"
import { setLang } from "@/i18n/serverContext" import "@scandic-hotels/design-system/style.css"
import type { Metadata } from "next" import TrpcProvider from "@/lib/trpc/Provider"
import InitLivePreview from "@/components/LivePreview"
import { getIntl } from "@/i18n"
import ServerIntlProvider from "@/i18n/Provider"
import { setLang } from "@/i18n/serverContext"
import type { LangParams, LayoutArgs } from "@/types/params" import type { LangParams, LayoutArgs } from "@/types/params"
export const metadata: Metadata = { export default async function RootLayout({
description: "New web",
title: "Scandic Hotels",
}
export default function RootLayout({
children, children,
params, params,
}: React.PropsWithChildren<LayoutArgs<LangParams>>) { }: React.PropsWithChildren<LayoutArgs<LangParams>>) {
setLang(params.lang) setLang(params.lang)
const { defaultLocale, locale, messages } = await getIntl()
return ( return (
<html lang={params.lang}> <html lang={params.lang}>
<body> <body>
<InitLivePreview /> <InitLivePreview />
{children} <ServerIntlProvider intl={{ defaultLocale, locale, messages }}>
<TrpcProvider>{children}</TrpcProvider>
</ServerIntlProvider>
</body> </body>
</html> </html>
) )

View File

@@ -1,6 +1,13 @@
import { ContentstackLivePreview } from "@contentstack/live-preview-utils"
import { notFound } from "next/navigation"
import ContentPage from "@/components/ContentType/ContentPage"
import HotelPage from "@/components/ContentType/HotelPage"
import LoyaltyPage from "@/components/ContentType/LoyaltyPage"
import LoadingSpinner from "@/components/LoadingSpinner"
import { setLang } from "@/i18n/serverContext" import { setLang } from "@/i18n/serverContext"
import { import type {
ContentTypeParams, ContentTypeParams,
LangParams, LangParams,
PageArgs, PageArgs,
@@ -13,12 +20,30 @@ export default async function PreviewPage({
}: PageArgs<LangParams & ContentTypeParams & UIDParams, {}>) { }: PageArgs<LangParams & ContentTypeParams & UIDParams, {}>) {
setLang(params.lang) setLang(params.lang)
return ( try {
<div> ContentstackLivePreview.setConfigFromParams(searchParams)
<p>
Preview for {params.contentType}:{params.uid} in {params.lang} with if (!searchParams.live_preview) {
params <pre>{JSON.stringify(searchParams, null, 2)}</pre> goes here return <LoadingSpinner />
</p> }
</div>
) switch (params.contentType) {
case "content-page":
return <ContentPage />
case "loyalty-page":
return <LoyaltyPage />
case "hotel-page":
return <HotelPage />
default:
console.log({ PREVIEW: params })
const type: never = params.contentType
console.error(`Unsupported content type given: ${type}`)
notFound()
}
} catch (error) {
// TODO: throw 500
console.error("Error in preview page")
console.error(error)
throw new Error("Something went wrong")
}
} }

View File

@@ -1,6 +1,6 @@
import Footer from "@/components/Current/Footer" import Footer from "@/components/Current/Footer"
import LangPopup from "@/components/Current/LangPopup" import LangPopup from "@/components/Current/LangPopup"
import InitLivePreview from "@/components/Current/LivePreview" import InitLivePreview from "@/components/LivePreview"
import SkipToMainContent from "@/components/SkipToMainContent" import SkipToMainContent from "@/components/SkipToMainContent"
import { setLang } from "@/i18n/serverContext" import { setLang } from "@/i18n/serverContext"

View File

@@ -1,4 +1,4 @@
import ContentstackLivePreview from "@contentstack/live-preview-utils" import { ContentstackLivePreview } from "@contentstack/live-preview-utils"
import { previewRequest } from "@/lib/graphql/previewRequest" import { previewRequest } from "@/lib/graphql/previewRequest"
import { GetCurrentBlockPage } from "@/lib/graphql/Query/Current/CurrentBlockPage.graphql" import { GetCurrentBlockPage } from "@/lib/graphql/Query/Current/CurrentBlockPage.graphql"

View File

@@ -1,6 +1,6 @@
"use client" "use client"
import ContentstackLivePreview from "@contentstack/live-preview-utils" import { ContentstackLivePreview } from "@contentstack/live-preview-utils"
import { useEffect } from "react" import { useEffect } from "react"
export default function InitLivePreview() { export default function InitLivePreview() {

View File

@@ -1,5 +1,6 @@
import "server-only" import "server-only"
import { ContentstackLivePreview } from "@contentstack/live-preview-utils"
import { ClientError, GraphQLClient } from "graphql-request" import { ClientError, GraphQLClient } from "graphql-request"
import { Lang } from "@/constants/languages" import { Lang } from "@/constants/languages"
@@ -16,6 +17,17 @@ export async function request<T>(
params?: RequestInit params?: RequestInit
): Promise<Data<T>> { ): Promise<Data<T>> {
try { try {
client.setHeaders({
access_token: env.CMS_ACCESS_TOKEN,
"Content-Type": "application/json",
})
const previewHash = ContentstackLivePreview.hash
if (previewHash) {
client.setEndpoint(env.CMS_PREVIEW_URL)
client.setHeader("preview_token", env.CMS_PREVIEW_TOKEN)
client.setHeader("live_preview", previewHash)
} else {
if (params?.cache) { if (params?.cache) {
client.requestConfig.cache = params.cache client.requestConfig.cache = params.cache
} }
@@ -46,12 +58,15 @@ export async function request<T>(
console.log({ console.log({
referenceDepth: rawResponse.headers.get("x-reference-depth"), referenceDepth: rawResponse.headers.get("x-reference-depth"),
}) })
console.log({ resolverCost: rawResponse.headers.get("x-resolver-cost") }) console.log({
resolverCost: rawResponse.headers.get("x-resolver-cost"),
})
return { return {
data: rawResponse.data, data: rawResponse.data,
} }
} }
}
try { try {
// @ts-expect-error: query can be undefined (?) // @ts-expect-error: query can be undefined (?)
@@ -78,10 +93,6 @@ export async function request<T>(
const response = await client.request<T>({ const response = await client.request<T>({
document: query, document: query,
requestHeaders: {
access_token: env.CMS_ACCESS_TOKEN,
"Content-Type": "application/json",
},
variables, variables,
}) })

View File

@@ -1,6 +1,6 @@
import "server-only" import "server-only"
import ContentstackLivePreview from "@contentstack/live-preview-utils" import { ContentstackLivePreview } from "@contentstack/live-preview-utils"
import { request as graphqlRequest } from "graphql-request" import { request as graphqlRequest } from "graphql-request"
import { env } from "@/env/server" import { env } from "@/env/server"

View File

@@ -2,7 +2,6 @@ import { NextResponse } from "next/server"
import { notFound } from "@/server/errors/next" import { notFound } from "@/server/errors/next"
import { resolve as resolveEntry } from "@/utils/entry"
import { findLang } from "@/utils/languages" import { findLang } from "@/utils/languages"
import { removeTrailingSlash } from "@/utils/url" import { removeTrailingSlash } from "@/utils/url"
@@ -18,17 +17,21 @@ export const middleware: NextMiddleware = async (request) => {
const pathWithoutTrailingSlash = removeTrailingSlash(nextUrl.pathname) const pathWithoutTrailingSlash = removeTrailingSlash(nextUrl.pathname)
const pathNameWithoutLang = pathWithoutTrailingSlash.replace(`/${lang}`, "") const contentTypePathName = pathWithoutTrailingSlash.replace(`/${lang}`, "")
const isPreview = request.nextUrl.pathname.includes("/preview")
const searchParams = new URLSearchParams(request.nextUrl.searchParams) const searchParams = new URLSearchParams(request.nextUrl.searchParams)
const { contentType, uid } = await fetchAndCacheEntry( const { contentType, uid } = await fetchAndCacheEntry(
pathNameWithoutLang, isPreview
? contentTypePathName.replace("/preview", "")
: contentTypePathName,
lang lang
) )
if (!contentType || !uid) { if (!contentType || !uid) {
throw notFound( throw notFound(
`Unable to resolve CMS entry for locale "${lang}": ${pathNameWithoutLang}` `Unable to resolve CMS entry for locale "${lang}": ${contentTypePathName}`
) )
} }
const headers = getDefaultRequestHeaders(request) const headers = getDefaultRequestHeaders(request)
@@ -37,9 +40,9 @@ export const middleware: NextMiddleware = async (request) => {
const isCurrent = contentType ? contentType.indexOf("current") >= 0 : false const isCurrent = contentType ? contentType.indexOf("current") >= 0 : false
if (request.nextUrl.pathname.includes("/preview")) { if (isPreview) {
if (isCurrent) { if (isCurrent) {
searchParams.set("uri", pathNameWithoutLang.replace("/preview", "")) searchParams.set("uri", contentTypePathName.replace("/preview", ""))
return NextResponse.rewrite( return NextResponse.rewrite(
new URL(`/${lang}/preview-current?${searchParams.toString()}`, nextUrl), new URL(`/${lang}/preview-current?${searchParams.toString()}`, nextUrl),
{ {
@@ -65,7 +68,7 @@ export const middleware: NextMiddleware = async (request) => {
if (isCurrent) { if (isCurrent) {
searchParams.set("uid", uid) searchParams.set("uid", uid)
searchParams.set("uri", pathNameWithoutLang) searchParams.set("uri", contentTypePathName)
return NextResponse.rewrite( return NextResponse.rewrite(
new URL( new URL(
`/${lang}/current-content-page?${searchParams.toString()}`, `/${lang}/current-content-page?${searchParams.toString()}`,