feat(SW-2265): Added campaign-page

Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-06-10 06:35:43 +00:00
parent ead822fa62
commit ace5519869
25 changed files with 538 additions and 1 deletions

View File

@@ -4,6 +4,10 @@ import {
GetMyPagesBreadcrumbs,
GetMyPagesBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/AccountPage.graphql"
import {
GetCampaignPageBreadcrumbs,
GetCampaignPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/CampaignPage.graphql"
import {
GetCollectionPageBreadcrumbs,
GetCollectionPageBreadcrumbsRefs,
@@ -151,6 +155,17 @@ export const breadcrumbsQueryRouter = router({
},
variables
)
case PageContentTypeEnum.campaignPage:
return await getBreadcrumbs<{
campaign_page: RawBreadcrumbsSchema
}>(
{
dataKey: "campaign_page",
refQuery: GetCampaignPageBreadcrumbsRefs,
query: GetCampaignPageBreadcrumbs,
},
variables
)
case PageContentTypeEnum.collectionPage:
return await getBreadcrumbs<{
collection_page: RawBreadcrumbsSchema

View File

@@ -0,0 +1,5 @@
import { mergeRouters } from "@/server/trpc"
import { campaignPageQueryRouter } from "./query"
export const campaignPageRouter = mergeRouters(campaignPageQueryRouter)

View File

@@ -0,0 +1,32 @@
import { z } from "zod"
import { systemSchema } from "../schemas/system"
export const campaignPageSchema = z.object({
campaign_page: z.object({
title: z.string(),
campaign_identifier: z.string().nullish(),
heading: z.string(),
subheading: z.string().nullish(),
preamble: z.object({
is_two_columns: z.boolean().default(false),
first_column: z.string(),
second_column: z.string(),
}),
system: systemSchema.merge(
z.object({
created_at: z.string(),
updated_at: z.string(),
})
),
}),
trackingProps: z.object({
url: z.string(),
}),
})
export const campaignPageRefsSchema = z.object({
campaign_page: z.object({
system: systemSchema,
}),
})

View File

@@ -0,0 +1,125 @@
import {
GetCampaignPage,
GetCampaignPageRefs,
} from "@/lib/graphql/Query/CampaignPage/CampaignPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { createCounter } from "@/server/telemetry"
import { contentStackUidWithServiceProcedure, router } from "@/server/trpc"
import { generateRefsResponseTag } from "@/utils/generateTag"
import { campaignPageRefsSchema, campaignPageSchema } from "./output"
import { generatePageTags } from "./utils"
import {
TrackingChannelEnum,
type TrackingSDKPageData,
} from "@/types/components/tracking"
import type {
GetCampaignPageData,
GetCampaignPageRefsData,
} from "@/types/trpc/routers/contentstack/campaignPage"
export const campaignPageQueryRouter = router({
get: contentStackUidWithServiceProcedure.query(async ({ ctx }) => {
const { lang, uid } = ctx
const getCampaignPageRefsCounter = createCounter(
"trpc.contentstack",
"campaignPage.get.refs"
)
const metricsGetCampaignPageRefs = getCampaignPageRefsCounter.init({
lang,
uid,
})
metricsGetCampaignPageRefs.start()
const refsResponse = await request<GetCampaignPageRefsData>(
GetCampaignPageRefs,
{ locale: lang, uid },
{
key: generateRefsResponseTag(lang, uid),
ttl: "max",
}
)
if (!refsResponse.data) {
const notFoundError = notFound(refsResponse)
metricsGetCampaignPageRefs.noDataError()
throw notFoundError
}
const validatedRefsData = campaignPageRefsSchema.safeParse(
refsResponse.data
)
if (!validatedRefsData.success) {
metricsGetCampaignPageRefs.validationError(validatedRefsData.error)
return null
}
metricsGetCampaignPageRefs.success()
const tags = generatePageTags(validatedRefsData.data, lang)
const getCampaignPageCounter = createCounter(
"trpc.contentstack",
"campaignPage.get"
)
const metricsGetCampaignPage = getCampaignPageCounter.init({
lang,
uid,
})
metricsGetCampaignPage.start()
const response = await request<GetCampaignPageData>(
GetCampaignPage,
{
locale: lang,
uid,
},
{
key: tags,
ttl: "max",
}
)
if (!response.data) {
const notFoundError = notFound(response)
metricsGetCampaignPage.noDataError()
throw notFoundError
}
const validatedResponse = campaignPageSchema.safeParse(response.data)
if (!validatedResponse.success) {
metricsGetCampaignPage.validationError(validatedResponse.error)
return null
}
const campaignPage = validatedResponse.data.campaign_page
metricsGetCampaignPage.success()
const system = campaignPage.system
const pageName = `campaign-page`
const tracking: TrackingSDKPageData = {
pageId: system.uid,
domainLanguage: system.locale,
publishDate: system.updated_at,
createDate: system.created_at,
channel: TrackingChannelEnum["campaign-page"],
pageType: "campaign-page",
pageName,
siteSections: pageName,
siteVersion: "new-web",
}
return {
campaignPage,
tracking,
}
}),
})

View File

@@ -0,0 +1,11 @@
import { generateTag } from "@/utils/generateTag"
import type { CampaignPageRefs } from "@/types/trpc/routers/contentstack/campaignPage"
import type { Lang } from "@/constants/languages"
export function generatePageTags(
validatedData: CampaignPageRefs,
lang: Lang
): string[] {
return [generateTag(lang, validatedData.campaign_page.system.uid)].flat()
}

View File

@@ -3,6 +3,7 @@ import { router } from "@/server/trpc"
import { accountPageRouter } from "./accountPage"
import { baseRouter } from "./base"
import { breadcrumbsRouter } from "./breadcrumbs"
import { campaignPageRouter } from "./campaignPage"
import { collectionPageRouter } from "./collectionPage"
import { contentPageRouter } from "./contentPage"
import { destinationCityPageRouter } from "./destinationCityPage"
@@ -25,6 +26,7 @@ export const contentstackRouter = router({
hotelPage: hotelPageRouter,
languageSwitcher: languageSwitcherRouter,
loyaltyPage: loyaltyPageRouter,
campaignPage: campaignPageRouter,
collectionPage: collectionPageRouter,
contentPage: contentPageRouter,
destinationOverviewPage: destinationOverviewPageRouter,

View File

@@ -4,6 +4,10 @@ import {
GetDaDeEnUrlsAccountPage,
GetFiNoSvUrlsAccountPage,
} from "@/lib/graphql/Query/AccountPage/AccountPage.graphql"
import {
GetDaDeEnUrlsCampaignPage,
GetFiNoSvUrlsCampaignPage,
} from "@/lib/graphql/Query/CampaignPage/CampaignPage.graphql"
import {
GetDaDeEnUrlsCollectionPage,
GetFiNoSvUrlsCollectionPage,
@@ -95,6 +99,10 @@ export async function getUrlsOfAllLanguages(
daDeEnDocument = GetDaDeEnUrlsCurrentBlocksPage
fiNoSvDocument = GetFiNoSvUrlsCurrentBlocksPage
break
case PageContentTypeEnum.campaignPage:
daDeEnDocument = GetDaDeEnUrlsCampaignPage
fiNoSvDocument = GetFiNoSvUrlsCampaignPage
break
case PageContentTypeEnum.loyaltyPage:
daDeEnDocument = GetDaDeEnUrlsLoyaltyPage
fiNoSvDocument = GetFiNoSvUrlsLoyaltyPage

View File

@@ -85,7 +85,21 @@ export const rawMetadataSchema = z.object({
})
.nullish(),
heading: z.string().nullish(),
preamble: z.string().nullish(),
preamble: z
.union([
z.string(),
z.object({
first_column: z.string(),
}),
])
.transform((preamble) => {
if (typeof preamble === "string") {
return preamble
}
return preamble?.first_column || null
})
.nullish(),
header: z
.object({
heading: z.string().nullish(),

View File

@@ -2,6 +2,7 @@ import { cache } from "react"
import { env } from "@/env/server"
import { GetAccountPageMetadata } from "@/lib/graphql/Query/AccountPage/Metadata.graphql"
import { GetCampaignPageMetadata } from "@/lib/graphql/Query/CampaignPage/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"
@@ -128,6 +129,14 @@ export const metadataQueryRouter = router({
accountPageResponse.account_page
)
break
case PageContentTypeEnum.campaignPage:
const campaignPageResponse = await fetchMetadata<{
campaign_page: RawMetadataSchema
}>(GetCampaignPageMetadata, variables)
metadata = await getTransformedMetadata(
campaignPageResponse.campaign_page
)
break
case PageContentTypeEnum.collectionPage:
const collectionPageResponse = await fetchMetadata<{
collection_page: RawMetadataSchema

View File

@@ -2,6 +2,7 @@ import * as Sentry from "@sentry/nextjs"
import {
GetAccountPageSettings,
GetCampaignPageSettings,
GetCollectionPageSettings,
GetContentPageSettings,
GetCurrentBlocksPageSettings,
@@ -74,6 +75,7 @@ export const pageSettingsQueryRouter = router({
const graphqlQueriesForContentType: Record<PageContentTypeEnum, any> = {
[PageContentTypeEnum.accountPage]: GetAccountPageSettings,
[PageContentTypeEnum.campaignPage]: GetCampaignPageSettings,
[PageContentTypeEnum.collectionPage]: GetCollectionPageSettings,
[PageContentTypeEnum.contentPage]: GetContentPageSettings,
[PageContentTypeEnum.currentBlocksPage]: GetCurrentBlocksPageSettings,