diff --git a/app/[lang]/(live)/(public)/[contentType]/[uid]/page.tsx b/app/[lang]/(live)/(public)/[contentType]/[uid]/page.tsx
index 974ea7735..687f4450d 100644
--- a/app/[lang]/(live)/(public)/[contentType]/[uid]/page.tsx
+++ b/app/[lang]/(live)/(public)/[contentType]/[uid]/page.tsx
@@ -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
case PageContentTypeEnum.destinationOverviewPage:
return
+ case PageContentTypeEnum.destinationCountryPage:
+ return
+ case PageContentTypeEnum.destinationCityPage:
+ return
case PageContentTypeEnum.hotelPage:
if (env.HIDE_FOR_NEXT_RELEASE) {
return notFound()
diff --git a/components/ContentType/DestinationCityPage/destinationCityPage.module.css b/components/ContentType/DestinationCityPage/destinationCityPage.module.css
new file mode 100644
index 000000000..c58807d98
--- /dev/null
+++ b/components/ContentType/DestinationCityPage/destinationCityPage.module.css
@@ -0,0 +1,10 @@
+.pageContainer {
+ display: grid;
+ max-width: var(--max-width);
+}
+
+@media screen and (min-width: 768px) {
+ .pageContainer {
+ margin: 0 auto;
+ }
+}
diff --git a/components/ContentType/DestinationCityPage/index.tsx b/components/ContentType/DestinationCityPage/index.tsx
new file mode 100644
index 000000000..16dbedb62
--- /dev/null
+++ b/components/ContentType/DestinationCityPage/index.tsx
@@ -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 (
+ <>
+
+
Destination City Page
+
+
+
+
+ >
+ )
+}
diff --git a/components/ContentType/DestinationCountryPage/destinationCountryPage.module.css b/components/ContentType/DestinationCountryPage/destinationCountryPage.module.css
new file mode 100644
index 000000000..c58807d98
--- /dev/null
+++ b/components/ContentType/DestinationCountryPage/destinationCountryPage.module.css
@@ -0,0 +1,10 @@
+.pageContainer {
+ display: grid;
+ max-width: var(--max-width);
+}
+
+@media screen and (min-width: 768px) {
+ .pageContainer {
+ margin: 0 auto;
+ }
+}
diff --git a/components/ContentType/DestinationCountryPage/index.tsx b/components/ContentType/DestinationCountryPage/index.tsx
new file mode 100644
index 000000000..c49f1886e
--- /dev/null
+++ b/components/ContentType/DestinationCountryPage/index.tsx
@@ -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 (
+ <>
+
+
Destination Country Page
+
+
+
+
+ >
+ )
+}
diff --git a/components/TempDesignSystem/Breadcrumbs/variants.ts b/components/TempDesignSystem/Breadcrumbs/variants.ts
index 28ff76517..069af703f 100644
--- a/components/TempDesignSystem/Breadcrumbs/variants.ts
+++ b/components/TempDesignSystem/Breadcrumbs/variants.ts
@@ -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,
diff --git a/lib/graphql/Fragments/Breadcrumbs/Breadcrumbs.graphql b/lib/graphql/Fragments/Breadcrumbs/Breadcrumbs.graphql
index fdc5d2730..010dcf4ac 100644
--- a/lib/graphql/Fragments/Breadcrumbs/Breadcrumbs.graphql
+++ b/lib/graphql/Fragments/Breadcrumbs/Breadcrumbs.graphql
@@ -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
}
diff --git a/lib/graphql/Fragments/Breadcrumbs/DestinationCityPage.graphql b/lib/graphql/Fragments/Breadcrumbs/DestinationCityPage.graphql
new file mode 100644
index 000000000..67cd5d764
--- /dev/null
+++ b/lib/graphql/Fragments/Breadcrumbs/DestinationCityPage.graphql
@@ -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
+ }
+}
diff --git a/lib/graphql/Fragments/Breadcrumbs/DestinationCountryPage.graphql b/lib/graphql/Fragments/Breadcrumbs/DestinationCountryPage.graphql
new file mode 100644
index 000000000..1a856cf09
--- /dev/null
+++ b/lib/graphql/Fragments/Breadcrumbs/DestinationCountryPage.graphql
@@ -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
+ }
+}
diff --git a/lib/graphql/Fragments/Breadcrumbs/DestinationOverviewPage.graphql b/lib/graphql/Fragments/Breadcrumbs/DestinationOverviewPage.graphql
new file mode 100644
index 000000000..21dd61dbb
--- /dev/null
+++ b/lib/graphql/Fragments/Breadcrumbs/DestinationOverviewPage.graphql
@@ -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
+ }
+}
diff --git a/lib/graphql/Query/BookingWidgetToggle.graphql b/lib/graphql/Query/BookingWidgetToggle.graphql
index 412e0a5cc..d42cf7463 100644
--- a/lib/graphql/Query/BookingWidgetToggle.graphql
+++ b/lib/graphql/Query/BookingWidgetToggle.graphql
@@ -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) {
diff --git a/lib/graphql/Query/Breadcrumbs/DestinationCityPage.graphql b/lib/graphql/Query/Breadcrumbs/DestinationCityPage.graphql
new file mode 100644
index 000000000..13f0c6a1d
--- /dev/null
+++ b/lib/graphql/Query/Breadcrumbs/DestinationCityPage.graphql
@@ -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
+ }
+ }
+}
diff --git a/lib/graphql/Query/Breadcrumbs/DestinationCountryPage.graphql b/lib/graphql/Query/Breadcrumbs/DestinationCountryPage.graphql
new file mode 100644
index 000000000..d0215bc8b
--- /dev/null
+++ b/lib/graphql/Query/Breadcrumbs/DestinationCountryPage.graphql
@@ -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
+ }
+ }
+}
diff --git a/lib/graphql/Query/DestinationCityPage/DestinationCityPage.graphql b/lib/graphql/Query/DestinationCityPage/DestinationCityPage.graphql
new file mode 100644
index 000000000..111d72e0e
--- /dev/null
+++ b/lib/graphql/Query/DestinationCityPage/DestinationCityPage.graphql
@@ -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
+ }
+}
diff --git a/lib/graphql/Query/DestinationCityPage/Metadata.graphql b/lib/graphql/Query/DestinationCityPage/Metadata.graphql
new file mode 100644
index 000000000..e0b1074f9
--- /dev/null
+++ b/lib/graphql/Query/DestinationCityPage/Metadata.graphql
@@ -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
+ }
+ }
+}
diff --git a/lib/graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql b/lib/graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql
new file mode 100644
index 000000000..dd628e279
--- /dev/null
+++ b/lib/graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql
@@ -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
+ }
+}
diff --git a/lib/graphql/Query/DestinationCountryPage/Metadata.graphql b/lib/graphql/Query/DestinationCountryPage/Metadata.graphql
new file mode 100644
index 000000000..771e21255
--- /dev/null
+++ b/lib/graphql/Query/DestinationCountryPage/Metadata.graphql
@@ -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
+ }
+ }
+}
diff --git a/lib/graphql/Query/ResolveEntry.graphql b/lib/graphql/Query/ResolveEntry.graphql
index 29b0cb993..751291d38 100644
--- a/lib/graphql/Query/ResolveEntry.graphql
+++ b/lib/graphql/Query/ResolveEntry.graphql
@@ -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
+ }
}
diff --git a/lib/trpc/memoizedRequests/index.ts b/lib/trpc/memoizedRequests/index.ts
index 5e1903a18..b3e37157a 100644
--- a/lib/trpc/memoizedRequests/index.ts
+++ b/lib/trpc/memoizedRequests/index.ts
@@ -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()
+ }
+)
diff --git a/server/routers/contentstack/bookingwidget/output.ts b/server/routers/contentstack/bookingwidget/output.ts
index b88d4270c..088d51a05 100644
--- a/server/routers/contentstack/bookingwidget/output.ts
+++ b/server/routers/contentstack/bookingwidget/output.ts
@@ -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,
})
diff --git a/server/routers/contentstack/bookingwidget/query.ts b/server/routers/contentstack/bookingwidget/query.ts
index ed244011a..3a138c7f5 100644
--- a/server/routers/contentstack/bookingwidget/query.ts
+++ b/server/routers/contentstack/bookingwidget/query.ts
@@ -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
diff --git a/server/routers/contentstack/breadcrumbs/query.ts b/server/routers/contentstack/breadcrumbs/query.ts
index 5f9676ef3..c96bf59e9 100644
--- a/server/routers/contentstack/breadcrumbs/query.ts
+++ b/server/routers/contentstack/breadcrumbs/query.ts
@@ -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
diff --git a/server/routers/contentstack/destinationCityPage/index.ts b/server/routers/contentstack/destinationCityPage/index.ts
new file mode 100644
index 000000000..81765282f
--- /dev/null
+++ b/server/routers/contentstack/destinationCityPage/index.ts
@@ -0,0 +1,7 @@
+import { mergeRouters } from "@/server/trpc"
+
+import { destinationCityPageQueryRouter } from "./query"
+
+export const destinationCityPageRouter = mergeRouters(
+ destinationCityPageQueryRouter
+)
diff --git a/server/routers/contentstack/destinationCityPage/output.ts b/server/routers/contentstack/destinationCityPage/output.ts
new file mode 100644
index 000000000..54ec7d334
--- /dev/null
+++ b/server/routers/contentstack/destinationCityPage/output.ts
@@ -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,
+ }),
+})
diff --git a/server/routers/contentstack/destinationCityPage/query.ts b/server/routers/contentstack/destinationCityPage/query.ts
new file mode 100644
index 000000000..de6f6014e
--- /dev/null
+++ b/server/routers/contentstack/destinationCityPage/query.ts
@@ -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(
+ 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(
+ 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,
+ }
+ }),
+})
diff --git a/server/routers/contentstack/destinationCityPage/telemetry.ts b/server/routers/contentstack/destinationCityPage/telemetry.ts
new file mode 100644
index 000000000..92440d1ce
--- /dev/null
+++ b/server/routers/contentstack/destinationCityPage/telemetry.ts
@@ -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"
+)
diff --git a/server/routers/contentstack/destinationCountryPage/index.ts b/server/routers/contentstack/destinationCountryPage/index.ts
new file mode 100644
index 000000000..76da88a62
--- /dev/null
+++ b/server/routers/contentstack/destinationCountryPage/index.ts
@@ -0,0 +1,7 @@
+import { mergeRouters } from "@/server/trpc"
+
+import { destinationCountryPageQueryRouter } from "./query"
+
+export const destinationCountryPageRouter = mergeRouters(
+ destinationCountryPageQueryRouter
+)
diff --git a/server/routers/contentstack/destinationCountryPage/output.ts b/server/routers/contentstack/destinationCountryPage/output.ts
new file mode 100644
index 000000000..07d01ad7d
--- /dev/null
+++ b/server/routers/contentstack/destinationCountryPage/output.ts
@@ -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,
+ }),
+})
diff --git a/server/routers/contentstack/destinationCountryPage/query.ts b/server/routers/contentstack/destinationCountryPage/query.ts
new file mode 100644
index 000000000..48ede62e9
--- /dev/null
+++ b/server/routers/contentstack/destinationCountryPage/query.ts
@@ -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(
+ 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(
+ 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,
+ }
+ }),
+})
diff --git a/server/routers/contentstack/destinationCountryPage/telemetry.ts b/server/routers/contentstack/destinationCountryPage/telemetry.ts
new file mode 100644
index 000000000..5ba3445b3
--- /dev/null
+++ b/server/routers/contentstack/destinationCountryPage/telemetry.ts
@@ -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"
+)
diff --git a/server/routers/contentstack/index.ts b/server/routers/contentstack/index.ts
index c1c192bc5..9292f3fdd 100644
--- a/server/routers/contentstack/index.ts
+++ b/server/routers/contentstack/index.ts
@@ -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,
diff --git a/server/routers/contentstack/languageSwitcher/query.ts b/server/routers/contentstack/languageSwitcher/query.ts
index 88e9c32be..f852f2ade 100644
--- a/server/routers/contentstack/languageSwitcher/query.ts
+++ b/server/routers/contentstack/languageSwitcher/query.ts
@@ -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`)
diff --git a/server/routers/contentstack/metadata/query.ts b/server/routers/contentstack/metadata/query.ts
index 92ae60ef0..11c5b30b0 100644
--- a/server/routers/contentstack/metadata/query.ts
+++ b/server/routers/contentstack/metadata/query.ts
@@ -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
diff --git a/types/components/tracking.ts b/types/components/tracking.ts
index f39eada37..2e74204c5 100644
--- a/types/components/tracking.ts
+++ b/types/components/tracking.ts
@@ -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",
}
diff --git a/types/params.ts b/types/params.ts
index 24c59b915..4c4a9d304 100644
--- a/types/params.ts
+++ b/types/params.ts
@@ -24,6 +24,8 @@ export type ContentTypeParams = {
| PageContentTypeEnum.hotelPage
| PageContentTypeEnum.collectionPage
| PageContentTypeEnum.destinationOverviewPage
+ | PageContentTypeEnum.destinationCountryPage
+ | PageContentTypeEnum.destinationCityPage
}
export type ContentTypeWebviewParams = {
diff --git a/types/requests/contentType.ts b/types/requests/contentType.ts
index a081e0538..d41b3710c 100644
--- a/types/requests/contentType.ts
+++ b/types/requests/contentType.ts
@@ -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",
}
diff --git a/types/requests/entry.ts b/types/requests/entry.ts
index 475473c70..b9acc3fd7 100644
--- a/types/requests/entry.ts
+++ b/types/requests/entry.ts
@@ -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,
})
diff --git a/types/trpc/routers/contentstack/destinationCityPage.ts b/types/trpc/routers/contentstack/destinationCityPage.ts
new file mode 100644
index 000000000..352a18a24
--- /dev/null
+++ b/types/trpc/routers/contentstack/destinationCityPage.ts
@@ -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 {}
+export interface DestinationCityPage
+ extends z.output {}
+
+export interface GetDestinationCityPageRefsSchema
+ extends z.input {}
+
+export interface DestinationCityPageRefs
+ extends z.output {}
diff --git a/types/trpc/routers/contentstack/destinationCountryPage.ts b/types/trpc/routers/contentstack/destinationCountryPage.ts
new file mode 100644
index 000000000..c6b5b1688
--- /dev/null
+++ b/types/trpc/routers/contentstack/destinationCountryPage.ts
@@ -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 {}
+export interface DestinationCountryPage
+ extends z.output {}
+
+export interface GetDestinationCountryPageRefsSchema
+ extends z.input {}
+
+export interface DestinationCountryPageRefs
+ extends z.output {}
diff --git a/types/trpc/routers/contentstack/destinationOverviewPage.ts b/types/trpc/routers/contentstack/destinationOverviewPage.ts
index 02a4b7efa..b541697b9 100644
--- a/types/trpc/routers/contentstack/destinationOverviewPage.ts
+++ b/types/trpc/routers/contentstack/destinationOverviewPage.ts
@@ -7,7 +7,7 @@ import type {
export interface GetDestinationOverviewPageData
extends z.input {}
-export interface DestinationPage
+export interface DestinationOverviewPage
extends z.output {}
export interface GetDestinationOverviewPageRefsSchema