Merged in feat/SW-1449-destination-page (pull request #1195)

Feat/SW-1449 destination page

* feat(SW-1449): Added destination country page

* feat(SW-1449): added destination city page


Approved-by: Fredrik Thorsson
Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-01-21 13:57:19 +00:00
parent c98c7a2d6b
commit f962400474
40 changed files with 981 additions and 1 deletions

View File

@@ -5,6 +5,8 @@ import { isSignupPage } from "@/constants/routes/signup"
import { env } from "@/env/server"
import { getHotelPage } from "@/lib/trpc/memoizedRequests"
import DestinationCityPage from "@/components/ContentType/DestinationCityPage"
import DestinationCountryPage from "@/components/ContentType/DestinationCountryPage"
import DestinationOverviewPage from "@/components/ContentType/DestinationOverviewPage"
import HotelPage from "@/components/ContentType/HotelPage"
import LoyaltyPage from "@/components/ContentType/LoyaltyPage"
@@ -58,6 +60,10 @@ export default async function ContentTypePage({
return <LoyaltyPage />
case PageContentTypeEnum.destinationOverviewPage:
return <DestinationOverviewPage />
case PageContentTypeEnum.destinationCountryPage:
return <DestinationCountryPage />
case PageContentTypeEnum.destinationCityPage:
return <DestinationCityPage />
case PageContentTypeEnum.hotelPage:
if (env.HIDE_FOR_NEXT_RELEASE) {
return notFound()

View File

@@ -0,0 +1,10 @@
.pageContainer {
display: grid;
max-width: var(--max-width);
}
@media screen and (min-width: 768px) {
.pageContainer {
margin: 0 auto;
}
}

View File

@@ -0,0 +1,28 @@
import { Suspense } from "react"
import { getDestinationCityPage } from "@/lib/trpc/memoizedRequests"
import TrackingSDK from "@/components/TrackingSDK"
import styles from "./destinationCityPage.module.css"
export default async function DestinationCityPage() {
const pageData = await getDestinationCityPage()
if (!pageData) {
return null
}
const { tracking, destinationCityPage } = pageData
return (
<>
<div className={styles.pageContainer}>
<h1>Destination City Page</h1>
</div>
<Suspense fallback={null}>
<TrackingSDK pageData={tracking} />
</Suspense>
</>
)
}

View File

@@ -0,0 +1,10 @@
.pageContainer {
display: grid;
max-width: var(--max-width);
}
@media screen and (min-width: 768px) {
.pageContainer {
margin: 0 auto;
}
}

View File

@@ -0,0 +1,28 @@
import { Suspense } from "react"
import { getDestinationCountryPage } from "@/lib/trpc/memoizedRequests"
import TrackingSDK from "@/components/TrackingSDK"
import styles from "./destinationCountryPage.module.css"
export default async function DestinationCountryPage() {
const pageData = await getDestinationCountryPage()
if (!pageData) {
return null
}
const { tracking, destinationCountryPage } = pageData
return (
<>
<div className={styles.pageContainer}>
<h1>Destination Country Page</h1>
</div>
<Suspense fallback={null}>
<TrackingSDK pageData={tracking} />
</Suspense>
</>
)
}

View File

@@ -11,6 +11,8 @@ export const breadcrumbsVariants = cva(styles.breadcrumbs, {
[PageContentTypeEnum.contentPage]: styles.contentWidth,
[PageContentTypeEnum.collectionPage]: styles.contentWidth,
[PageContentTypeEnum.destinationOverviewPage]: styles.contentWidth,
[PageContentTypeEnum.destinationCountryPage]: styles.contentWidth,
[PageContentTypeEnum.destinationCityPage]: styles.contentWidth,
[PageContentTypeEnum.hotelPage]: styles.hotelHeaderWidth,
[PageContentTypeEnum.loyaltyPage]: styles.fullWidth,
default: styles.fullWidth,

View File

@@ -1,6 +1,9 @@
#import "./AccountPage.graphql"
#import "./CollectionPage.graphql"
#import "./ContentPage.graphql"
#import "./DestinationOverviewPage.graphql"
#import "./DestinationCountryPage.graphql"
#import "./DestinationCityPage.graphql"
#import "./HotelPage.graphql"
#import "./LoyaltyPage.graphql"
@@ -13,6 +16,9 @@ fragment Breadcrumbs on Breadcrumbs {
...AccountPageBreadcrumb
...CollectionPageBreadcrumb
...ContentPageBreadcrumb
...DestinationOverviewPageBreadcrumb
...DestinationCountryPageBreadcrumb
...DestinationCityPageBreadcrumb
...HotelPageBreadcrumb
...LoyaltyPageBreadcrumb
}
@@ -29,6 +35,9 @@ fragment BreadcrumbsRefs on Breadcrumbs {
...AccountPageBreadcrumbRef
...CollectionPageBreadcrumbRef
...ContentPageBreadcrumbRef
...DestinationOverviewPageBreadcrumbRef
...DestinationCountryPageBreadcrumbRef
...DestinationCityPageBreadcrumbRef
...HotelPageBreadcrumbRef
...LoyaltyPageBreadcrumbRef
}

View File

@@ -0,0 +1,24 @@
#import "../System.graphql"
fragment DestinationCityPageBreadcrumb on DestinationCityPage {
web {
breadcrumbs {
title
}
}
system {
...System
}
url
}
fragment DestinationCityPageBreadcrumbRef on DestinationCityPage {
web {
breadcrumbs {
title
}
}
system {
...System
}
}

View File

@@ -0,0 +1,24 @@
#import "../System.graphql"
fragment DestinationCountryPageBreadcrumb on DestinationCountryPage {
web {
breadcrumbs {
title
}
}
system {
...System
}
url
}
fragment DestinationCountryPageBreadcrumbRef on DestinationCountryPage {
web {
breadcrumbs {
title
}
}
system {
...System
}
}

View File

@@ -0,0 +1,24 @@
#import "../System.graphql"
fragment DestinationOverviewPageBreadcrumb on DestinationOverviewPage {
web {
breadcrumbs {
title
}
}
system {
...System
}
url
}
fragment DestinationOverviewPageBreadcrumbRef on DestinationOverviewPage {
web {
breadcrumbs {
title
}
}
system {
...System
}
}

View File

@@ -36,6 +36,20 @@ query GetDestinationOverviewPageSettings($uid: String!, $locale: String!) {
}
}
}
query GetDestinationCountryPageSettings($uid: String!, $locale: String!) {
destination_country_page(uid: $uid, locale: $locale) {
page_settings {
hide_booking_widget
}
}
}
query GetDestinationCityPageSettings($uid: String!, $locale: String!) {
destination_city_page(uid: $uid, locale: $locale) {
page_settings {
hide_booking_widget
}
}
}
query GetHotelPageSettings($uid: String!, $locale: String!) {
hotel_page(uid: $uid, locale: $locale) {

View File

@@ -0,0 +1,28 @@
#import "../../Fragments/Breadcrumbs/Breadcrumbs.graphql"
#import "../../Fragments/System.graphql"
query GetDestinationCityPageBreadcrumbs($locale: String!, $uid: String!) {
destination_city_page(locale: $locale, uid: $uid) {
web {
breadcrumbs {
...Breadcrumbs
}
}
system {
...System
}
}
}
query GetDestinationCityPageBreadcrumbsRefs($locale: String!, $uid: String!) {
destination_city_page(locale: $locale, uid: $uid) {
web {
breadcrumbs {
...BreadcrumbsRefs
}
}
system {
...System
}
}
}

View File

@@ -0,0 +1,31 @@
#import "../../Fragments/Breadcrumbs/Breadcrumbs.graphql"
#import "../../Fragments/System.graphql"
query GetDestinationCountryPageBreadcrumbs($locale: String!, $uid: String!) {
destination_country_page(locale: $locale, uid: $uid) {
web {
breadcrumbs {
...Breadcrumbs
}
}
system {
...System
}
}
}
query GetDestinationCountryPageBreadcrumbsRefs(
$locale: String!
$uid: String!
) {
destination_country_page(locale: $locale, uid: $uid) {
web {
breadcrumbs {
...BreadcrumbsRefs
}
}
system {
...System
}
}
}

View File

@@ -0,0 +1,47 @@
#import "../../Fragments/System.graphql"
query GetDestinationCityPage($locale: String!, $uid: String!) {
destination_city_page(uid: $uid, locale: $locale) {
title
system {
...System
created_at
updated_at
}
}
trackingProps: destination_city_page(locale: "en", uid: $uid) {
url
}
}
query GetDestinationCityPageRefs($locale: String!, $uid: String!) {
destination_city_page(locale: $locale, uid: $uid) {
system {
...System
}
}
}
query GetDaDeEnUrlsDestinationCityPage($uid: String!) {
de: destination_city_page(locale: "de", uid: $uid) {
url
}
en: destination_city_page(locale: "en", uid: $uid) {
url
}
da: destination_city_page(locale: "da", uid: $uid) {
url
}
}
query GetFiNoSvUrlsDestinationCityPage($uid: String!) {
fi: destination_city_page(locale: "fi", uid: $uid) {
url
}
no: destination_city_page(locale: "no", uid: $uid) {
url
}
sv: destination_city_page(locale: "sv", uid: $uid) {
url
}
}

View File

@@ -0,0 +1,18 @@
#import "../../Fragments/Metadata.graphql"
#import "../../Fragments/System.graphql"
query GetDestinationCityPageMetadata($locale: String!, $uid: String!) {
destination_city_page(locale: $locale, uid: $uid) {
web {
breadcrumbs {
title
}
seo_metadata {
...Metadata
}
}
system {
...System
}
}
}

View File

@@ -0,0 +1,47 @@
#import "../../Fragments/System.graphql"
query GetDestinationCountryPage($locale: String!, $uid: String!) {
destination_country_page(uid: $uid, locale: $locale) {
title
system {
...System
created_at
updated_at
}
}
trackingProps: destination_country_page(locale: "en", uid: $uid) {
url
}
}
query GetDestinationCountryPageRefs($locale: String!, $uid: String!) {
destination_country_page(locale: $locale, uid: $uid) {
system {
...System
}
}
}
query GetDaDeEnUrlsDestinationCountryPage($uid: String!) {
de: destination_country_page(locale: "de", uid: $uid) {
url
}
en: destination_country_page(locale: "en", uid: $uid) {
url
}
da: destination_country_page(locale: "da", uid: $uid) {
url
}
}
query GetFiNoSvUrlsDestinationCountryPage($uid: String!) {
fi: destination_country_page(locale: "fi", uid: $uid) {
url
}
no: destination_country_page(locale: "no", uid: $uid) {
url
}
sv: destination_country_page(locale: "sv", uid: $uid) {
url
}
}

View File

@@ -0,0 +1,18 @@
#import "../../Fragments/Metadata.graphql"
#import "../../Fragments/System.graphql"
query GetDestinationCountryPageMetadata($locale: String!, $uid: String!) {
destination_country_page(locale: $locale, uid: $uid) {
web {
breadcrumbs {
title
}
seo_metadata {
...Metadata
}
}
system {
...System
}
}
}

View File

@@ -60,4 +60,20 @@ query EntryByUrlBatch2($locale: String!, $url: String!) {
}
total
}
all_destination_country_page(where: { url: $url }, locale: $locale) {
items {
system {
...System
}
}
total
}
all_destination_city_page(where: { url: $url }, locale: $locale) {
items {
system {
...System
}
}
total
}
}

View File

@@ -176,3 +176,13 @@ export const getDestinationOverviewPage = cache(
return serverClient().contentstack.destinationOverviewPage.get()
}
)
export const getDestinationCountryPage = cache(
async function getMemoizedDestinationCountryPage() {
return serverClient().contentstack.destinationCountryPage.get()
}
)
export const getDestinationCityPage = cache(
async function getMemoizedDestinationCityPage() {
return serverClient().contentstack.destinationCityPage.get()
}
)

View File

@@ -14,6 +14,8 @@ export const validateBookingWidgetToggleSchema = z.object({
content_page: bookingWidgetToggleSchema,
current_blocks_page: bookingWidgetToggleSchema,
destination_overview_page: bookingWidgetToggleSchema,
destination_country_page: bookingWidgetToggleSchema,
destination_city_page: bookingWidgetToggleSchema,
hotel_page: bookingWidgetToggleSchema,
loyalty_page: bookingWidgetToggleSchema,
})

View File

@@ -3,6 +3,8 @@ import {
GetCollectionPageSettings,
GetContentPageSettings,
GetCurrentBlocksPageSettings,
GetDestinationCityPageSettings,
GetDestinationCountryPageSettings,
GetDestinationOverviewPageSettings,
GetHotelPageSettings,
GetLoyaltyPageSettings,
@@ -54,6 +56,12 @@ export const bookingwidgetQueryRouter = router({
case PageContentTypeEnum.destinationOverviewPage:
GetPageSettings = GetDestinationOverviewPageSettings
break
case PageContentTypeEnum.destinationCountryPage:
GetPageSettings = GetDestinationCountryPageSettings
break
case PageContentTypeEnum.destinationCityPage:
GetPageSettings = GetDestinationCityPageSettings
break
case PageContentTypeEnum.hotelPage:
GetPageSettings = GetHotelPageSettings
break

View File

@@ -13,6 +13,14 @@ import {
GetContentPageBreadcrumbs,
GetContentPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/ContentPage.graphql"
import {
GetDestinationCityPageBreadcrumbs,
GetDestinationCityPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/DestinationCityPage.graphql"
import {
GetDestinationCountryPageBreadcrumbs,
GetDestinationCountryPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/DestinationCountryPage.graphql"
import {
GetDestinationOverviewPageBreadcrumbs,
GetDestinationOverviewPageBreadcrumbsRefs,
@@ -218,6 +226,28 @@ export const breadcrumbsQueryRouter = router({
},
variables
)
case PageContentTypeEnum.destinationCountryPage:
return await getBreadcrumbs<{
destination_country_page: RawBreadcrumbsSchema
}>(
{
dataKey: "destination_country_page",
refQuery: GetDestinationCountryPageBreadcrumbsRefs,
query: GetDestinationCountryPageBreadcrumbs,
},
variables
)
case PageContentTypeEnum.destinationCityPage:
return await getBreadcrumbs<{
destination_city_page: RawBreadcrumbsSchema
}>(
{
dataKey: "destination_city_page",
refQuery: GetDestinationCityPageBreadcrumbsRefs,
query: GetDestinationCityPageBreadcrumbs,
},
variables
)
case PageContentTypeEnum.hotelPage:
return await getBreadcrumbs<{
hotel_page: RawBreadcrumbsSchema

View File

@@ -0,0 +1,7 @@
import { mergeRouters } from "@/server/trpc"
import { destinationCityPageQueryRouter } from "./query"
export const destinationCityPageRouter = mergeRouters(
destinationCityPageQueryRouter
)

View File

@@ -0,0 +1,25 @@
import { z } from "zod"
import { systemSchema } from "../schemas/system"
export const destinationCityPageSchema = z.object({
destination_city_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 destinationCityPageRefsSchema = z.object({
destination_city_page: z.object({
system: systemSchema,
}),
})

View File

@@ -0,0 +1,179 @@
import {
GetDestinationCityPage,
GetDestinationCityPageRefs,
} from "@/lib/graphql/Query/DestinationCityPage/DestinationCityPage.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 {
destinationCityPageRefsSchema,
destinationCityPageSchema,
} from "./output"
import {
getDestinationCityPageCounter,
getDestinationCityPageFailCounter,
getDestinationCityPageRefsCounter,
getDestinationCityPageRefsFailCounter,
getDestinationCityPageRefsSuccessCounter,
getDestinationCityPageSuccessCounter,
} from "./telemetry"
import {
TrackingChannelEnum,
type TrackingSDKPageData,
} from "@/types/components/tracking"
import type {
GetDestinationCityPageData,
GetDestinationCityPageRefsSchema,
} from "@/types/trpc/routers/contentstack/destinationCityPage"
export const destinationCityPageQueryRouter = router({
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
const { lang, uid } = ctx
getDestinationCityPageRefsCounter.add(1, { lang, uid })
console.info(
"contentstack.destinationCityPage.refs start",
JSON.stringify({ query: { lang, uid } })
)
const refsResponse = await request<GetDestinationCityPageRefsSchema>(
GetDestinationCityPageRefs,
{ locale: lang, uid },
{
cache: "force-cache",
next: {
tags: [generateTag(lang, uid)],
},
}
)
if (!refsResponse.data) {
const notFoundError = notFound(refsResponse)
getDestinationCityPageRefsFailCounter.add(1, {
lang,
uid: `${uid}`,
error_type: "not_found",
error: JSON.stringify({ code: notFoundError.code }),
})
console.error(
"contentstack.destinationCityPage.refs not found error",
JSON.stringify({
query: { lang, uid },
error: { code: notFoundError.code },
})
)
throw notFoundError
}
const validatedRefsData = destinationCityPageRefsSchema.safeParse(
refsResponse.data
)
if (!validatedRefsData.success) {
getDestinationCityPageRefsFailCounter.add(1, {
lang,
uid: `${uid}`,
error_type: "validation_error",
error: JSON.stringify(validatedRefsData.error),
})
console.error(
"contentstack.destinationCityPage.refs validation error",
JSON.stringify({ query: { lang, uid }, error: validatedRefsData.error })
)
return null
}
getDestinationCityPageRefsSuccessCounter.add(1, { lang, uid: `${uid}` })
console.info(
"contentstack.destinationCityPage.refs success",
JSON.stringify({ query: { lang, uid } })
)
getDestinationCityPageCounter.add(1, { lang, uid: `${uid}` })
console.info(
"contentstack.destinationCityPage start",
JSON.stringify({
query: { lang, uid },
})
)
const response = await request<GetDestinationCityPageData>(
GetDestinationCityPage,
{
locale: lang,
uid,
},
{
cache: "force-cache",
next: {
tags: [generateTag(lang, uid)],
},
}
)
if (!response.data) {
const notFoundError = notFound(response)
getDestinationCityPageFailCounter.add(1, {
lang,
uid: `${uid}`,
error_type: "not_found",
error: JSON.stringify({ code: notFoundError.code }),
})
console.error(
"contentstack.destinationCityPage not found error",
JSON.stringify({
query: { lang, uid },
error: { code: notFoundError.code },
})
)
throw notFoundError
}
const destinationCityPage = destinationCityPageSchema.safeParse(
response.data
)
if (!destinationCityPage.success) {
getDestinationCityPageFailCounter.add(1, {
lang,
uid: `${uid}`,
error_type: "validation_error",
error: JSON.stringify(destinationCityPage.error),
})
console.error(
"contentstack.destinationCityPage validation error",
JSON.stringify({
query: { lang, uid },
error: destinationCityPage.error,
})
)
return null
}
getDestinationCityPageSuccessCounter.add(1, { lang, uid: `${uid}` })
console.info(
"contentstack.destinationCityPage success",
JSON.stringify({
query: { lang, uid },
})
)
const system = destinationCityPage.data.destination_city_page.system
const tracking: TrackingSDKPageData = {
pageId: system.uid,
domainLanguage: lang,
publishDate: system.updated_at,
createDate: system.created_at,
channel: TrackingChannelEnum["destination-page"],
pageType: "staticcontentpage",
pageName: destinationCityPage.data.trackingProps.url,
siteSections: destinationCityPage.data.trackingProps.url,
siteVersion: "new-web",
}
return {
destinationCityPage: destinationCityPage.data.destination_city_page,
tracking,
}
}),
})

View File

@@ -0,0 +1,23 @@
import { metrics } from "@opentelemetry/api"
const meter = metrics.getMeter("trpc.contentstack.destinationCityPage")
export const getDestinationCityPageRefsCounter = meter.createCounter(
"trpc.contentstack.destinationCityPage.get"
)
export const getDestinationCityPageRefsFailCounter = meter.createCounter(
"trpc.contentstack.destinationCityPage.get-fail"
)
export const getDestinationCityPageRefsSuccessCounter = meter.createCounter(
"trpc.contentstack.destinationCityPage.get-success"
)
export const getDestinationCityPageCounter = meter.createCounter(
"trpc.contentstack.destinationCityPage.get"
)
export const getDestinationCityPageSuccessCounter = meter.createCounter(
"trpc.contentstack.destinationCityPage.get-success"
)
export const getDestinationCityPageFailCounter = meter.createCounter(
"trpc.contentstack.destinationCityPage.get-fail"
)

View File

@@ -0,0 +1,7 @@
import { mergeRouters } from "@/server/trpc"
import { destinationCountryPageQueryRouter } from "./query"
export const destinationCountryPageRouter = mergeRouters(
destinationCountryPageQueryRouter
)

View File

@@ -0,0 +1,25 @@
import { z } from "zod"
import { systemSchema } from "../schemas/system"
export const destinationCountryPageSchema = z.object({
destination_country_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 destinationCountryPageRefsSchema = z.object({
destination_country_page: z.object({
system: systemSchema,
}),
})

View File

@@ -0,0 +1,180 @@
import {
GetDestinationCountryPage,
GetDestinationCountryPageRefs,
} from "@/lib/graphql/Query/DestinationCountryPage/DestinationCountryPage.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 {
destinationCountryPageRefsSchema,
destinationCountryPageSchema,
} from "./output"
import {
getDestinationCountryPageCounter,
getDestinationCountryPageFailCounter,
getDestinationCountryPageRefsCounter,
getDestinationCountryPageRefsFailCounter,
getDestinationCountryPageRefsSuccessCounter,
getDestinationCountryPageSuccessCounter,
} from "./telemetry"
import {
TrackingChannelEnum,
type TrackingSDKPageData,
} from "@/types/components/tracking"
import type {
GetDestinationCountryPageData,
GetDestinationCountryPageRefsSchema,
} from "@/types/trpc/routers/contentstack/destinationCountryPage"
export const destinationCountryPageQueryRouter = router({
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
const { lang, uid } = ctx
getDestinationCountryPageRefsCounter.add(1, { lang, uid })
console.info(
"contentstack.destinationCountryPage.refs start",
JSON.stringify({ query: { lang, uid } })
)
const refsResponse = await request<GetDestinationCountryPageRefsSchema>(
GetDestinationCountryPageRefs,
{ locale: lang, uid },
{
cache: "force-cache",
next: {
tags: [generateTag(lang, uid)],
},
}
)
if (!refsResponse.data) {
const notFoundError = notFound(refsResponse)
getDestinationCountryPageRefsFailCounter.add(1, {
lang,
uid: `${uid}`,
error_type: "not_found",
error: JSON.stringify({ code: notFoundError.code }),
})
console.error(
"contentstack.destinationCountryPage.refs not found error",
JSON.stringify({
query: { lang, uid },
error: { code: notFoundError.code },
})
)
throw notFoundError
}
const validatedRefsData = destinationCountryPageRefsSchema.safeParse(
refsResponse.data
)
if (!validatedRefsData.success) {
getDestinationCountryPageRefsFailCounter.add(1, {
lang,
uid: `${uid}`,
error_type: "validation_error",
error: JSON.stringify(validatedRefsData.error),
})
console.error(
"contentstack.destinationCountryPage.refs validation error",
JSON.stringify({ query: { lang, uid }, error: validatedRefsData.error })
)
return null
}
getDestinationCountryPageRefsSuccessCounter.add(1, { lang, uid: `${uid}` })
console.info(
"contentstack.destinationCountryPage.refs success",
JSON.stringify({ query: { lang, uid } })
)
getDestinationCountryPageCounter.add(1, { lang, uid: `${uid}` })
console.info(
"contentstack.destinationCountryPage start",
JSON.stringify({
query: { lang, uid },
})
)
const response = await request<GetDestinationCountryPageData>(
GetDestinationCountryPage,
{
locale: lang,
uid,
},
{
cache: "force-cache",
next: {
tags: [generateTag(lang, uid)],
},
}
)
if (!response.data) {
const notFoundError = notFound(response)
getDestinationCountryPageFailCounter.add(1, {
lang,
uid: `${uid}`,
error_type: "not_found",
error: JSON.stringify({ code: notFoundError.code }),
})
console.error(
"contentstack.destinationCountryPage not found error",
JSON.stringify({
query: { lang, uid },
error: { code: notFoundError.code },
})
)
throw notFoundError
}
const destinationCountryPage = destinationCountryPageSchema.safeParse(
response.data
)
if (!destinationCountryPage.success) {
getDestinationCountryPageFailCounter.add(1, {
lang,
uid: `${uid}`,
error_type: "validation_error",
error: JSON.stringify(destinationCountryPage.error),
})
console.error(
"contentstack.destinationCountryPage validation error",
JSON.stringify({
query: { lang, uid },
error: destinationCountryPage.error,
})
)
return null
}
getDestinationCountryPageSuccessCounter.add(1, { lang, uid: `${uid}` })
console.info(
"contentstack.destinationCountryPage success",
JSON.stringify({
query: { lang, uid },
})
)
const system = destinationCountryPage.data.destination_country_page.system
const tracking: TrackingSDKPageData = {
pageId: system.uid,
domainLanguage: lang,
publishDate: system.updated_at,
createDate: system.created_at,
channel: TrackingChannelEnum["destination-page"],
pageType: "staticcontentpage",
pageName: destinationCountryPage.data.trackingProps.url,
siteSections: destinationCountryPage.data.trackingProps.url,
siteVersion: "new-web",
}
return {
destinationCountryPage:
destinationCountryPage.data.destination_country_page,
tracking,
}
}),
})

View File

@@ -0,0 +1,23 @@
import { metrics } from "@opentelemetry/api"
const meter = metrics.getMeter("trpc.contentstack.destinationCountryPage")
export const getDestinationCountryPageRefsCounter = meter.createCounter(
"trpc.contentstack.destinationCountryPage.get"
)
export const getDestinationCountryPageRefsFailCounter = meter.createCounter(
"trpc.contentstack.destinationCountryPage.get-fail"
)
export const getDestinationCountryPageRefsSuccessCounter = meter.createCounter(
"trpc.contentstack.destinationCountryPage.get-success"
)
export const getDestinationCountryPageCounter = meter.createCounter(
"trpc.contentstack.destinationCountryPage.get"
)
export const getDestinationCountryPageSuccessCounter = meter.createCounter(
"trpc.contentstack.destinationCountryPage.get-success"
)
export const getDestinationCountryPageFailCounter = meter.createCounter(
"trpc.contentstack.destinationCountryPage.get-fail"
)

View File

@@ -6,6 +6,8 @@ import { bookingwidgetRouter } from "./bookingwidget"
import { breadcrumbsRouter } from "./breadcrumbs"
import { collectionPageRouter } from "./collectionPage"
import { contentPageRouter } from "./contentPage"
import { destinationCityPageRouter } from "./destinationCityPage"
import { destinationCountryPageRouter } from "./destinationCountryPage"
import { destinationOverviewPageRouter } from "./destinationOverviewPage"
import { hotelPageRouter } from "./hotelPage"
import { languageSwitcherRouter } from "./languageSwitcher"
@@ -26,6 +28,8 @@ export const contentstackRouter = router({
collectionPage: collectionPageRouter,
contentPage: contentPageRouter,
destinationOverviewPage: destinationOverviewPageRouter,
destinationCountryPage: destinationCountryPageRouter,
destinationCityPage: destinationCityPageRouter,
myPages: myPagesRouter,
metadata: metadataRouter,
rewards: rewardRouter,

View File

@@ -19,6 +19,14 @@ import {
GetDaDeEnUrlsCurrentBlocksPage,
GetFiNoSvUrlsCurrentBlocksPage,
} from "@/lib/graphql/Query/Current/LanguageSwitcher.graphql"
import {
GetDaDeEnUrlsDestinationCityPage,
GetFiNoSvUrlsDestinationCityPage,
} from "@/lib/graphql/Query/DestinationCityPage/DestinationCityPage.graphql"
import {
GetDaDeEnUrlsDestinationCountryPage,
GetFiNoSvUrlsDestinationCountryPage,
} from "@/lib/graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql"
import {
GetDaDeEnUrlsDestinationOverviewPage,
GetFiNoSvUrlsDestinationOverviewPage,
@@ -104,6 +112,14 @@ async function getLanguageSwitcher(options: LanguageSwitcherVariables) {
daDeEnDocument = GetDaDeEnUrlsDestinationOverviewPage
fiNoSvDocument = GetFiNoSvUrlsDestinationOverviewPage
break
case PageContentTypeEnum.destinationCountryPage:
daDeEnDocument = GetDaDeEnUrlsDestinationCountryPage
fiNoSvDocument = GetFiNoSvUrlsDestinationCountryPage
break
case PageContentTypeEnum.destinationCityPage:
daDeEnDocument = GetDaDeEnUrlsDestinationCityPage
fiNoSvDocument = GetFiNoSvUrlsDestinationCityPage
break
default:
console.error(`type: [${options.contentType}]`)
console.error(`Trying to get a content type that is not supported`)

View File

@@ -4,6 +4,8 @@ import { cache } from "react"
import { GetAccountPageMetadata } from "@/lib/graphql/Query/AccountPage/Metadata.graphql"
import { GetCollectionPageMetadata } from "@/lib/graphql/Query/CollectionPage/Metadata.graphql"
import { GetContentPageMetadata } from "@/lib/graphql/Query/ContentPage/Metadata.graphql"
import { GetDestinationCityPageMetadata } from "@/lib/graphql/Query/DestinationCityPage/Metadata.graphql"
import { GetDestinationCountryPageMetadata } from "@/lib/graphql/Query/DestinationCountryPage/Metadata.graphql"
import { GetDestinationOverviewPageMetadata } from "@/lib/graphql/Query/DestinationOverviewPage/Metadata.graphql"
import { GetHotelPageMetadata } from "@/lib/graphql/Query/HotelPage/Metadata.graphql"
import { GetLoyaltyPageMetadata } from "@/lib/graphql/Query/LoyaltyPage/Metadata.graphql"
@@ -144,6 +146,20 @@ export const metadataQueryRouter = router({
return getTransformedMetadata(
destinationOverviewPageResponse.destination_overview_page
)
case PageContentTypeEnum.destinationCountryPage:
const destinationCountryPageResponse = await fetchMetadata<{
destination_country_page: RawMetadataSchema
}>(GetDestinationCountryPageMetadata, variables)
return getTransformedMetadata(
destinationCountryPageResponse.destination_country_page
)
case PageContentTypeEnum.destinationCityPage:
const destinationCityPageResponse = await fetchMetadata<{
destination_city_page: RawMetadataSchema
}>(GetDestinationCityPageMetadata, variables)
return getTransformedMetadata(
destinationCityPageResponse.destination_city_page
)
case PageContentTypeEnum.loyaltyPage:
const loyaltyPageResponse = await fetchMetadata<{
loyalty_page: RawMetadataSchema

View File

@@ -7,6 +7,7 @@ export enum TrackingChannelEnum {
"hotelreservation" = "hotelreservation",
"collection-page" = "collection-page",
"destination-overview-page" = "destination-overview-page",
"destination-page" = "destination-page",
"hotels" = "hotels",
}

View File

@@ -24,6 +24,8 @@ export type ContentTypeParams = {
| PageContentTypeEnum.hotelPage
| PageContentTypeEnum.collectionPage
| PageContentTypeEnum.destinationOverviewPage
| PageContentTypeEnum.destinationCountryPage
| PageContentTypeEnum.destinationCityPage
}
export type ContentTypeWebviewParams = {

View File

@@ -4,6 +4,8 @@ export enum PageContentTypeEnum {
contentPage = "content_page",
currentBlocksPage = "current_blocks_page",
destinationOverviewPage = "destination_overview_page",
destinationCountryPage = "destination_country_page",
destinationCityPage = "destination_city_page",
hotelPage = "hotel_page",
loyaltyPage = "loyalty_page",
}

View File

@@ -20,4 +20,6 @@ export const validateEntryResolveSchema = z.object({
all_current_blocks_page: entryResolveSchema,
all_hotel_page: entryResolveSchema,
all_destination_overview_page: entryResolveSchema,
all_destination_country_page: entryResolveSchema,
all_destination_city_page: entryResolveSchema,
})

View File

@@ -0,0 +1,17 @@
import type { z } from "zod"
import type {
destinationCityPageRefsSchema,
destinationCityPageSchema,
} from "@/server/routers/contentstack/destinationCityPage/output"
export interface GetDestinationCityPageData
extends z.input<typeof destinationCityPageSchema> {}
export interface DestinationCityPage
extends z.output<typeof destinationCityPageSchema> {}
export interface GetDestinationCityPageRefsSchema
extends z.input<typeof destinationCityPageRefsSchema> {}
export interface DestinationCityPageRefs
extends z.output<typeof destinationCityPageRefsSchema> {}

View File

@@ -0,0 +1,17 @@
import type { z } from "zod"
import type {
destinationCountryPageRefsSchema,
destinationCountryPageSchema,
} from "@/server/routers/contentstack/destinationCountryPage/output"
export interface GetDestinationCountryPageData
extends z.input<typeof destinationCountryPageSchema> {}
export interface DestinationCountryPage
extends z.output<typeof destinationCountryPageSchema> {}
export interface GetDestinationCountryPageRefsSchema
extends z.input<typeof destinationCountryPageRefsSchema> {}
export interface DestinationCountryPageRefs
extends z.output<typeof destinationCountryPageRefsSchema> {}

View File

@@ -7,7 +7,7 @@ import type {
export interface GetDestinationOverviewPageData
extends z.input<typeof destinationOverviewPageSchema> {}
export interface DestinationPage
export interface DestinationOverviewPage
extends z.output<typeof destinationOverviewPageSchema> {}
export interface GetDestinationOverviewPageRefsSchema