) {
setLang(params.lang)
- const intl = await getIntl()
-
return (
- {intl.formatMessage(
- { id: "Middleware error {lang}: {status}" },
- {
- lang: params.lang,
- status: params.status,
- }
- )}
+ Middleware error {params.lang}: {params.status}
)
}
diff --git a/components/ContentType/StartPage/index.tsx b/components/ContentType/StartPage/index.tsx
new file mode 100644
index 000000000..c7c817b81
--- /dev/null
+++ b/components/ContentType/StartPage/index.tsx
@@ -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 (
+
+ {JSON.stringify(content, null, 2)}
+
+
+
+
+ )
+}
diff --git a/components/TempDesignSystem/Breadcrumbs/variants.ts b/components/TempDesignSystem/Breadcrumbs/variants.ts
index 069af703f..35fa1963f 100644
--- a/components/TempDesignSystem/Breadcrumbs/variants.ts
+++ b/components/TempDesignSystem/Breadcrumbs/variants.ts
@@ -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,
},
},
diff --git a/lib/graphql/Query/ResolveEntry.graphql b/lib/graphql/Query/ResolveEntry.graphql
index 751291d38..e68014288 100644
--- a/lib/graphql/Query/ResolveEntry.graphql
+++ b/lib/graphql/Query/ResolveEntry.graphql
@@ -76,4 +76,12 @@ query EntryByUrlBatch2($locale: String!, $url: String!) {
}
total
}
+ all_start_page(where: { url: $url }, locale: $locale) {
+ items {
+ system {
+ ...System
+ }
+ }
+ total
+ }
}
diff --git a/lib/graphql/Query/StartPage/StartPage.graphql b/lib/graphql/Query/StartPage/StartPage.graphql
new file mode 100644
index 000000000..4a8beb1e8
--- /dev/null
+++ b/lib/graphql/Query/StartPage/StartPage.graphql
@@ -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
+ }
+}
diff --git a/lib/trpc/memoizedRequests/index.ts b/lib/trpc/memoizedRequests/index.ts
index b3e37157a..d9c381a11 100644
--- a/lib/trpc/memoizedRequests/index.ts
+++ b/lib/trpc/memoizedRequests/index.ts
@@ -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()
+})
diff --git a/server/routers/contentstack/bookingwidget/output.ts b/server/routers/contentstack/bookingwidget/output.ts
index 088d51a05..6a74712b6 100644
--- a/server/routers/contentstack/bookingwidget/output.ts
+++ b/server/routers/contentstack/bookingwidget/output.ts
@@ -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<
diff --git a/server/routers/contentstack/index.ts b/server/routers/contentstack/index.ts
index 9292f3fdd..29bbbb1a4 100644
--- a/server/routers/contentstack/index.ts
+++ b/server/routers/contentstack/index.ts
@@ -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,
})
diff --git a/server/routers/contentstack/languageSwitcher/query.ts b/server/routers/contentstack/languageSwitcher/query.ts
index f852f2ade..15da48696 100644
--- a/server/routers/contentstack/languageSwitcher/query.ts
+++ b/server/routers/contentstack/languageSwitcher/query.ts
@@ -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`)
diff --git a/server/routers/contentstack/startPage/index.ts b/server/routers/contentstack/startPage/index.ts
new file mode 100644
index 000000000..c8236f2a6
--- /dev/null
+++ b/server/routers/contentstack/startPage/index.ts
@@ -0,0 +1,5 @@
+import { mergeRouters } from "@/server/trpc"
+
+import { startPageQueryRouter } from "./query"
+
+export const startPageRouter = mergeRouters(startPageQueryRouter)
diff --git a/server/routers/contentstack/startPage/output.ts b/server/routers/contentstack/startPage/output.ts
new file mode 100644
index 000000000..b63a000b1
--- /dev/null
+++ b/server/routers/contentstack/startPage/output.ts
@@ -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,
+ }),
+})
diff --git a/server/routers/contentstack/startPage/query.ts b/server/routers/contentstack/startPage/query.ts
new file mode 100644
index 000000000..d6cdf1986
--- /dev/null
+++ b/server/routers/contentstack/startPage/query.ts
@@ -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(
+ 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(
+ 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,
+ }
+ }),
+})
diff --git a/server/routers/contentstack/startPage/telemetry.ts b/server/routers/contentstack/startPage/telemetry.ts
new file mode 100644
index 000000000..e5296f3e1
--- /dev/null
+++ b/server/routers/contentstack/startPage/telemetry.ts
@@ -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"
+)
diff --git a/types/components/tracking.ts b/types/components/tracking.ts
index 2e74204c5..29fe50f06 100644
--- a/types/components/tracking.ts
+++ b/types/components/tracking.ts
@@ -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
diff --git a/types/params.ts b/types/params.ts
index 4c4a9d304..ae2a69fcc 100644
--- a/types/params.ts
+++ b/types/params.ts
@@ -26,6 +26,7 @@ export type ContentTypeParams = {
| PageContentTypeEnum.destinationOverviewPage
| PageContentTypeEnum.destinationCountryPage
| PageContentTypeEnum.destinationCityPage
+ | PageContentTypeEnum.startPage
}
export type ContentTypeWebviewParams = {
diff --git a/types/requests/contentType.ts b/types/requests/contentType.ts
index d41b3710c..3ab996f27 100644
--- a/types/requests/contentType.ts
+++ b/types/requests/contentType.ts
@@ -8,4 +8,5 @@ export enum PageContentTypeEnum {
destinationCityPage = "destination_city_page",
hotelPage = "hotel_page",
loyaltyPage = "loyalty_page",
+ startPage = "start_page",
}
diff --git a/types/requests/entry.ts b/types/requests/entry.ts
index b9acc3fd7..47e17fa8e 100644
--- a/types/requests/entry.ts
+++ b/types/requests/entry.ts
@@ -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,
})
diff --git a/types/trpc/routers/contentstack/startPage.ts b/types/trpc/routers/contentstack/startPage.ts
new file mode 100644
index 000000000..8966d1569
--- /dev/null
+++ b/types/trpc/routers/contentstack/startPage.ts
@@ -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 {}
+export interface StartPage extends z.output {}
+
+export interface GetStartPageRefsSchema
+ extends z.input {}
+
+export interface StartPageRefs extends z.output {}
diff --git a/utils/entry.ts b/utils/entry.ts
index d66cf8ca5..452b90d67 100644
--- a/utils/entry.ts
+++ b/utils/entry.ts
@@ -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,