Merged in feat/SW-1381-new-startpage-page (pull request #1197)
feat(SW-1381): add initial start page * feat(SW-1381): add initial start page * fix: remove unused startpage template remove translation key for middleware error page * fix(SW-1381): add tracking SDK and feature flag to hide start page Approved-by: Erik Tiekstra Approved-by: Matilda Landström Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
@@ -10,6 +10,7 @@ import DestinationCountryPage from "@/components/ContentType/DestinationCountryP
|
||||
import DestinationOverviewPage from "@/components/ContentType/DestinationOverviewPage"
|
||||
import HotelPage from "@/components/ContentType/HotelPage"
|
||||
import LoyaltyPage from "@/components/ContentType/LoyaltyPage"
|
||||
import StartPage from "@/components/ContentType/StartPage"
|
||||
import CollectionPage from "@/components/ContentType/StaticPages/CollectionPage"
|
||||
import ContentPage from "@/components/ContentType/StaticPages/ContentPage"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
@@ -74,6 +75,11 @@ export default async function ContentTypePage({
|
||||
) : (
|
||||
notFound()
|
||||
)
|
||||
case PageContentTypeEnum.startPage:
|
||||
if (env.HIDE_FOR_NEXT_RELEASE) {
|
||||
return notFound()
|
||||
}
|
||||
return <StartPage />
|
||||
default:
|
||||
const type: never = params.contentType
|
||||
console.error(`Unsupported content type given: ${type}`)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { getIntl } from "@/i18n"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
@@ -10,17 +9,9 @@ export default async function MiddlewareError({
|
||||
}: LayoutArgs<LangParams & StatusParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const intl = await getIntl()
|
||||
|
||||
return (
|
||||
<div className={styles.layout}>
|
||||
{intl.formatMessage(
|
||||
{ id: "Middleware error {lang}: {status}" },
|
||||
{
|
||||
lang: params.lang,
|
||||
status: params.status,
|
||||
}
|
||||
)}
|
||||
Middleware error {params.lang}: {params.status}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
21
components/ContentType/StartPage/index.tsx
Normal file
21
components/ContentType/StartPage/index.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Suspense } from "react"
|
||||
|
||||
import { getStartPage } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
|
||||
export default async function StartPage() {
|
||||
const content = await getStartPage()
|
||||
if (!content) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<p>
|
||||
<code>{JSON.stringify(content, null, 2)}</code>
|
||||
<Suspense fallback={null}>
|
||||
<TrackingSDK pageData={content.tracking} />
|
||||
</Suspense>
|
||||
</p>
|
||||
)
|
||||
}
|
||||
@@ -15,6 +15,7 @@ export const breadcrumbsVariants = cva(styles.breadcrumbs, {
|
||||
[PageContentTypeEnum.destinationCityPage]: styles.contentWidth,
|
||||
[PageContentTypeEnum.hotelPage]: styles.hotelHeaderWidth,
|
||||
[PageContentTypeEnum.loyaltyPage]: styles.fullWidth,
|
||||
[PageContentTypeEnum.startPage]: styles.contentWidth,
|
||||
default: styles.fullWidth,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -76,4 +76,12 @@ query EntryByUrlBatch2($locale: String!, $url: String!) {
|
||||
}
|
||||
total
|
||||
}
|
||||
all_start_page(where: { url: $url }, locale: $locale) {
|
||||
items {
|
||||
system {
|
||||
...System
|
||||
}
|
||||
}
|
||||
total
|
||||
}
|
||||
}
|
||||
|
||||
47
lib/graphql/Query/StartPage/StartPage.graphql
Normal file
47
lib/graphql/Query/StartPage/StartPage.graphql
Normal file
@@ -0,0 +1,47 @@
|
||||
#import "../../Fragments/System.graphql"
|
||||
|
||||
query GetStartPage($locale: String!, $uid: String!) {
|
||||
start_page(uid: $uid, locale: $locale) {
|
||||
title
|
||||
url
|
||||
system {
|
||||
...System
|
||||
created_at
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
trackingProps: start_page(locale: "en", uid: $uid) {
|
||||
url
|
||||
}
|
||||
}
|
||||
|
||||
query GetStartPageRefs($locale: String!, $uid: String!) {
|
||||
start_page(locale: $locale, uid: $uid) {
|
||||
system {
|
||||
...System
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query GetDaDeEnUrlsStartPage($uid: String!) {
|
||||
de: start_page(locale: "de", uid: $uid) {
|
||||
url
|
||||
}
|
||||
en: start_page(locale: "en", uid: $uid) {
|
||||
url
|
||||
}
|
||||
da: start_page(locale: "da", uid: $uid) {
|
||||
url
|
||||
}
|
||||
}
|
||||
query GetFiNoSvUrlsStartPage($uid: String!) {
|
||||
fi: start_page(locale: "fi", uid: $uid) {
|
||||
url
|
||||
}
|
||||
no: start_page(locale: "no", uid: $uid) {
|
||||
url
|
||||
}
|
||||
sv: start_page(locale: "sv", uid: $uid) {
|
||||
url
|
||||
}
|
||||
}
|
||||
@@ -186,3 +186,7 @@ export const getDestinationCityPage = cache(
|
||||
return serverClient().contentstack.destinationCityPage.get()
|
||||
}
|
||||
)
|
||||
|
||||
export const getStartPage = cache(async function getMemoizedStartPage() {
|
||||
return serverClient().contentstack.startPage.get()
|
||||
})
|
||||
|
||||
@@ -18,6 +18,7 @@ export const validateBookingWidgetToggleSchema = z.object({
|
||||
destination_city_page: bookingWidgetToggleSchema,
|
||||
hotel_page: bookingWidgetToggleSchema,
|
||||
loyalty_page: bookingWidgetToggleSchema,
|
||||
start_page: bookingWidgetToggleSchema,
|
||||
})
|
||||
|
||||
export type ValidateBookingWidgetToggleType = z.infer<
|
||||
|
||||
@@ -16,6 +16,7 @@ import { loyaltyPageRouter } from "./loyaltyPage"
|
||||
import { metadataRouter } from "./metadata"
|
||||
import { myPagesRouter } from "./myPages"
|
||||
import { rewardRouter } from "./reward"
|
||||
import { startPageRouter } from "./startPage"
|
||||
|
||||
export const contentstackRouter = router({
|
||||
accountPage: accountPageRouter,
|
||||
@@ -34,4 +35,5 @@ export const contentstackRouter = router({
|
||||
metadata: metadataRouter,
|
||||
rewards: rewardRouter,
|
||||
loyaltyLevels: loyaltyLevelRouter,
|
||||
startPage: startPageRouter,
|
||||
})
|
||||
|
||||
@@ -39,6 +39,10 @@ import {
|
||||
GetDaDeEnUrlsLoyaltyPage,
|
||||
GetFiNoSvUrlsLoyaltyPage,
|
||||
} from "@/lib/graphql/Query/LoyaltyPage/LoyaltyPage.graphql"
|
||||
import {
|
||||
GetDaDeEnUrlsStartPage,
|
||||
GetFiNoSvUrlsStartPage,
|
||||
} from "@/lib/graphql/Query/StartPage/StartPage.graphql"
|
||||
import { internalServerError } from "@/server/errors/trpc"
|
||||
import { publicProcedure, router } from "@/server/trpc"
|
||||
|
||||
@@ -120,6 +124,10 @@ async function getLanguageSwitcher(options: LanguageSwitcherVariables) {
|
||||
daDeEnDocument = GetDaDeEnUrlsDestinationCityPage
|
||||
fiNoSvDocument = GetFiNoSvUrlsDestinationCityPage
|
||||
break
|
||||
case PageContentTypeEnum.startPage:
|
||||
daDeEnDocument = GetDaDeEnUrlsStartPage
|
||||
fiNoSvDocument = GetFiNoSvUrlsStartPage
|
||||
break
|
||||
default:
|
||||
console.error(`type: [${options.contentType}]`)
|
||||
console.error(`Trying to get a content type that is not supported`)
|
||||
|
||||
5
server/routers/contentstack/startPage/index.ts
Normal file
5
server/routers/contentstack/startPage/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { mergeRouters } from "@/server/trpc"
|
||||
|
||||
import { startPageQueryRouter } from "./query"
|
||||
|
||||
export const startPageRouter = mergeRouters(startPageQueryRouter)
|
||||
25
server/routers/contentstack/startPage/output.ts
Normal file
25
server/routers/contentstack/startPage/output.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
export const startPageSchema = z.object({
|
||||
start_page: z.object({
|
||||
title: z.string(),
|
||||
system: systemSchema.merge(
|
||||
z.object({
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
trackingProps: z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
/** REFS */
|
||||
export const startPageRefsSchema = z.object({
|
||||
start_page: z.object({
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
182
server/routers/contentstack/startPage/query.ts
Normal file
182
server/routers/contentstack/startPage/query.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
import {
|
||||
GetStartPage,
|
||||
GetStartPageRefs,
|
||||
} from "@/lib/graphql/Query/StartPage/StartPage.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { notFound } from "@/server/errors/trpc"
|
||||
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
|
||||
import { generateTag } from "@/utils/generateTag"
|
||||
|
||||
import { startPageRefsSchema, startPageSchema } from "./output"
|
||||
import {
|
||||
getStartPageCounter,
|
||||
getStartPageFailCounter,
|
||||
getStartPageRefsCounter,
|
||||
getStartPageRefsFailCounter,
|
||||
getStartPageRefsSuccessCounter,
|
||||
getStartPageSuccessCounter,
|
||||
} from "./telemetry"
|
||||
|
||||
import {
|
||||
TrackingChannelEnum,
|
||||
type TrackingSDKPageData,
|
||||
} from "@/types/components/tracking"
|
||||
import type {
|
||||
GetStartPageData,
|
||||
GetStartPageRefsSchema,
|
||||
} from "@/types/trpc/routers/contentstack/startPage"
|
||||
|
||||
export const startPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
getStartPageRefsCounter.add(1, { lang, uid: `${uid}` })
|
||||
console.info(
|
||||
"contentstack.startPage.refs start",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
})
|
||||
)
|
||||
const refsResponse = await request<GetStartPageRefsSchema>(
|
||||
GetStartPageRefs,
|
||||
{
|
||||
locale: lang,
|
||||
uid,
|
||||
},
|
||||
{
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: [generateTag(lang, uid)],
|
||||
},
|
||||
}
|
||||
)
|
||||
if (!refsResponse.data) {
|
||||
const notFoundError = notFound(refsResponse)
|
||||
getStartPageRefsFailCounter.add(1, {
|
||||
lang,
|
||||
uid,
|
||||
error_type: "not_found",
|
||||
error: JSON.stringify({ code: notFoundError.code }),
|
||||
})
|
||||
console.error(
|
||||
"contentstack.startPage.refs not found error",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
error: { code: notFoundError.code },
|
||||
})
|
||||
)
|
||||
throw notFoundError
|
||||
}
|
||||
|
||||
const validatedRefsData = startPageRefsSchema.safeParse(refsResponse.data)
|
||||
|
||||
if (!validatedRefsData.success) {
|
||||
getStartPageRefsFailCounter.add(1, {
|
||||
lang,
|
||||
uid,
|
||||
error_type: "validation_error",
|
||||
error: JSON.stringify(validatedRefsData.error),
|
||||
})
|
||||
console.error(
|
||||
"contentstack.startPage.refs validation error",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
error: validatedRefsData.error,
|
||||
})
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
getStartPageRefsSuccessCounter.add(1, { lang, uid: `${uid}` })
|
||||
console.info(
|
||||
"contentstack.startPage.refs success",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
})
|
||||
)
|
||||
|
||||
getStartPageCounter.add(1, { lang, uid: `${uid}` })
|
||||
console.info(
|
||||
"contentstack.startPage start",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
})
|
||||
)
|
||||
const response = await request<GetStartPageData>(
|
||||
GetStartPage,
|
||||
{
|
||||
locale: lang,
|
||||
uid,
|
||||
},
|
||||
{
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: [generateTag(lang, uid)],
|
||||
},
|
||||
}
|
||||
)
|
||||
if (!response.data) {
|
||||
const notFoundError = notFound(response)
|
||||
getStartPageFailCounter.add(1, {
|
||||
lang,
|
||||
uid: `${uid}`,
|
||||
error_type: "not_found",
|
||||
error: JSON.stringify({ code: notFoundError.code }),
|
||||
})
|
||||
console.error(
|
||||
"contentstack.startPage not found error",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
error: { code: notFoundError.code },
|
||||
})
|
||||
)
|
||||
throw notFoundError
|
||||
}
|
||||
|
||||
const startPage = startPageSchema.safeParse(response.data)
|
||||
|
||||
if (!startPage.success) {
|
||||
getStartPageFailCounter.add(1, {
|
||||
lang,
|
||||
uid: `${uid}`,
|
||||
error_type: "validation_error",
|
||||
error: JSON.stringify(startPage.error),
|
||||
})
|
||||
console.error(
|
||||
"contentstack.startPage validation error",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
error: startPage.error,
|
||||
})
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
getStartPageSuccessCounter.add(1, { lang, uid: `${uid}` })
|
||||
console.info(
|
||||
"contentstack.startPage success",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
})
|
||||
)
|
||||
|
||||
const system = startPage.data.start_page.system
|
||||
const tracking: TrackingSDKPageData = {
|
||||
pageId: system.uid,
|
||||
domainLanguage: lang,
|
||||
publishDate: system.updated_at,
|
||||
createDate: system.created_at,
|
||||
channel: TrackingChannelEnum["start-page"],
|
||||
pageType: "start-page",
|
||||
pageName: startPage.data.trackingProps.url,
|
||||
siteSections: startPage.data.trackingProps.url,
|
||||
siteVersion: "new-web",
|
||||
}
|
||||
|
||||
return {
|
||||
startPage: startPage.data.start_page,
|
||||
tracking,
|
||||
}
|
||||
}),
|
||||
})
|
||||
23
server/routers/contentstack/startPage/telemetry.ts
Normal file
23
server/routers/contentstack/startPage/telemetry.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { metrics } from "@opentelemetry/api"
|
||||
|
||||
const meter = metrics.getMeter("trpc.contentstack.startPage")
|
||||
|
||||
export const getStartPageRefsCounter = meter.createCounter(
|
||||
"trpc.contentstack.startPage.get"
|
||||
)
|
||||
export const getStartPageRefsFailCounter = meter.createCounter(
|
||||
"trpc.contentstack.startPage.get-fail"
|
||||
)
|
||||
export const getStartPageRefsSuccessCounter = meter.createCounter(
|
||||
"trpc.contentstack.startPage.get-success"
|
||||
)
|
||||
|
||||
export const getStartPageCounter = meter.createCounter(
|
||||
"trpc.contentstack.startPage.get"
|
||||
)
|
||||
export const getStartPageSuccessCounter = meter.createCounter(
|
||||
"trpc.contentstack.startPage.get-success"
|
||||
)
|
||||
export const getStartPageFailCounter = meter.createCounter(
|
||||
"trpc.contentstack.startPage.get-fail"
|
||||
)
|
||||
@@ -9,6 +9,7 @@ export enum TrackingChannelEnum {
|
||||
"destination-overview-page" = "destination-overview-page",
|
||||
"destination-page" = "destination-page",
|
||||
"hotels" = "hotels",
|
||||
"start-page" = "start-page",
|
||||
}
|
||||
|
||||
export type TrackingChannel = keyof typeof TrackingChannelEnum
|
||||
|
||||
@@ -26,6 +26,7 @@ export type ContentTypeParams = {
|
||||
| PageContentTypeEnum.destinationOverviewPage
|
||||
| PageContentTypeEnum.destinationCountryPage
|
||||
| PageContentTypeEnum.destinationCityPage
|
||||
| PageContentTypeEnum.startPage
|
||||
}
|
||||
|
||||
export type ContentTypeWebviewParams = {
|
||||
|
||||
@@ -8,4 +8,5 @@ export enum PageContentTypeEnum {
|
||||
destinationCityPage = "destination_city_page",
|
||||
hotelPage = "hotel_page",
|
||||
loyaltyPage = "loyalty_page",
|
||||
startPage = "start_page",
|
||||
}
|
||||
|
||||
@@ -22,4 +22,5 @@ export const validateEntryResolveSchema = z.object({
|
||||
all_destination_overview_page: entryResolveSchema,
|
||||
all_destination_country_page: entryResolveSchema,
|
||||
all_destination_city_page: entryResolveSchema,
|
||||
all_start_page: entryResolveSchema,
|
||||
})
|
||||
|
||||
14
types/trpc/routers/contentstack/startPage.ts
Normal file
14
types/trpc/routers/contentstack/startPage.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { z } from "zod"
|
||||
|
||||
import type {
|
||||
startPageRefsSchema,
|
||||
startPageSchema,
|
||||
} from "@/server/routers/contentstack/startPage/output"
|
||||
|
||||
export interface GetStartPageData extends z.input<typeof startPageSchema> {}
|
||||
export interface StartPage extends z.output<typeof startPageSchema> {}
|
||||
|
||||
export interface GetStartPageRefsSchema
|
||||
extends z.input<typeof startPageRefsSchema> {}
|
||||
|
||||
export interface StartPageRefs extends z.output<typeof startPageRefsSchema> {}
|
||||
@@ -9,7 +9,10 @@ import { internalServerError } from "@/server/errors/next"
|
||||
import { validateEntryResolveSchema } from "@/types/requests/entry"
|
||||
|
||||
export async function resolve(url: string, lang = Lang.en) {
|
||||
const variables = { locale: lang, url }
|
||||
const variables = { locale: lang, url: url || "/" }
|
||||
|
||||
// The maximum amount of content types you can query is 6, therefor more
|
||||
// than that is being batched
|
||||
const response = await batchEdgeRequest([
|
||||
{
|
||||
document: EntryByUrlBatch1,
|
||||
|
||||
Reference in New Issue
Block a user