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 { setLang } from "@/i18n/serverContext"
import "@/app/globals.css"
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"
export const metadata: Metadata = {
description: "New web",
title: "Scandic Hotels",
}
export default function RootLayout({
export default async function RootLayout({
children,
params,
}: React.PropsWithChildren<LayoutArgs<LangParams>>) {
setLang(params.lang)
const { defaultLocale, locale, messages } = await getIntl()
return (
<html lang={params.lang}>
<body>
<InitLivePreview />
{children}
<ServerIntlProvider intl={{ defaultLocale, locale, messages }}>
<TrpcProvider>{children}</TrpcProvider>
</ServerIntlProvider>
</body>
</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 {
import type {
ContentTypeParams,
LangParams,
PageArgs,
@@ -13,12 +20,30 @@ export default async function PreviewPage({
}: PageArgs<LangParams & ContentTypeParams & UIDParams, {}>) {
setLang(params.lang)
return (
<div>
<p>
Preview for {params.contentType}:{params.uid} in {params.lang} with
params <pre>{JSON.stringify(searchParams, null, 2)}</pre> goes here
</p>
</div>
)
try {
ContentstackLivePreview.setConfigFromParams(searchParams)
if (!searchParams.live_preview) {
return <LoadingSpinner />
}
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 LangPopup from "@/components/Current/LangPopup"
import InitLivePreview from "@/components/Current/LivePreview"
import InitLivePreview from "@/components/LivePreview"
import SkipToMainContent from "@/components/SkipToMainContent"
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 { GetCurrentBlockPage } from "@/lib/graphql/Query/Current/CurrentBlockPage.graphql"

View File

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

View File

@@ -1,5 +1,6 @@
import "server-only"
import { ContentstackLivePreview } from "@contentstack/live-preview-utils"
import { ClientError, GraphQLClient } from "graphql-request"
import { Lang } from "@/constants/languages"
@@ -16,40 +17,54 @@ export async function request<T>(
params?: RequestInit
): Promise<Data<T>> {
try {
if (params?.cache) {
client.requestConfig.cache = params.cache
}
if (params?.headers) {
client.requestConfig.headers = params.headers
}
if (params?.next) {
client.requestConfig.next = params.next
}
client.setHeaders({
access_token: env.CMS_ACCESS_TOKEN,
"Content-Type": "application/json",
})
if (env.PRINT_QUERY) {
const print = (await import("graphql/language/printer")).print
const rawResponse = await client.rawRequest<T>(
print(query as DocumentNode),
variables,
{
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) {
client.requestConfig.cache = params.cache
}
if (params?.headers) {
client.requestConfig.headers = params.headers
}
if (params?.next) {
client.requestConfig.next = params.next
}
if (env.PRINT_QUERY) {
const print = (await import("graphql/language/printer")).print
const rawResponse = await client.rawRequest<T>(
print(query as DocumentNode),
variables,
{
access_token: env.CMS_ACCESS_TOKEN,
"Content-Type": "application/json",
}
)
/**
* TODO: Send to Monitoring (Logging and Metrics)
*/
console.log({
complexityLimit: rawResponse.headers.get("x-query-complexity"),
})
console.log({
referenceDepth: rawResponse.headers.get("x-reference-depth"),
})
console.log({
resolverCost: rawResponse.headers.get("x-resolver-cost"),
})
return {
data: rawResponse.data,
}
)
/**
* TODO: Send to Monitoring (Logging and Metrics)
*/
console.log({
complexityLimit: rawResponse.headers.get("x-query-complexity"),
})
console.log({
referenceDepth: rawResponse.headers.get("x-reference-depth"),
})
console.log({ resolverCost: rawResponse.headers.get("x-resolver-cost") })
return {
data: rawResponse.data,
}
}
@@ -78,10 +93,6 @@ export async function request<T>(
const response = await client.request<T>({
document: query,
requestHeaders: {
access_token: env.CMS_ACCESS_TOKEN,
"Content-Type": "application/json",
},
variables,
})

View File

@@ -1,6 +1,6 @@
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 { env } from "@/env/server"

View File

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