feat(SW-508): preview for content pages
This commit is contained in:
@@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -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,40 +17,54 @@ export async function request<T>(
|
|||||||
params?: RequestInit
|
params?: RequestInit
|
||||||
): Promise<Data<T>> {
|
): Promise<Data<T>> {
|
||||||
try {
|
try {
|
||||||
if (params?.cache) {
|
client.setHeaders({
|
||||||
client.requestConfig.cache = params.cache
|
access_token: env.CMS_ACCESS_TOKEN,
|
||||||
}
|
"Content-Type": "application/json",
|
||||||
if (params?.headers) {
|
})
|
||||||
client.requestConfig.headers = params.headers
|
|
||||||
}
|
|
||||||
if (params?.next) {
|
|
||||||
client.requestConfig.next = params.next
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env.PRINT_QUERY) {
|
const previewHash = ContentstackLivePreview.hash
|
||||||
const print = (await import("graphql/language/printer")).print
|
if (previewHash) {
|
||||||
const rawResponse = await client.rawRequest<T>(
|
client.setEndpoint(env.CMS_PREVIEW_URL)
|
||||||
print(query as DocumentNode),
|
client.setHeader("preview_token", env.CMS_PREVIEW_TOKEN)
|
||||||
variables,
|
client.setHeader("live_preview", previewHash)
|
||||||
{
|
} else {
|
||||||
access_token: env.CMS_ACCESS_TOKEN,
|
if (params?.cache) {
|
||||||
"Content-Type": "application/json",
|
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>({
|
const response = await client.request<T>({
|
||||||
document: query,
|
document: query,
|
||||||
requestHeaders: {
|
|
||||||
access_token: env.CMS_ACCESS_TOKEN,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
variables,
|
variables,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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()}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user