feat(SW-2973): Added bookingCode if available to links inside campaign pages

* feat(SW-2973): Moved block types to trpc lib

Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-07-04 10:15:01 +00:00
parent fa7214cb58
commit 270249c6c4
44 changed files with 187 additions and 115 deletions

View File

@@ -28,6 +28,9 @@ query GetCampaignPage($locale: String!, $uid: String!) {
...Accordion_CampaignPage
...HotelListing_CampaignPage
}
page_settings {
booking_code
}
system {
...System
created_at

View File

@@ -18,6 +18,7 @@ import {
linkConnectionSchema,
} from "../schemas/linkConnection"
import { systemSchema } from "../schemas/system"
import { getCarouselCardsBlockWithBookingCodeLinks } from "./utils"
const campaignPageEssentials = z
.object({
@@ -123,6 +124,11 @@ export const campaignPageSchema = z
second_column: z.string(),
}),
blocks: discriminatedUnionArray(blocksSchema.options),
page_settings: z
.object({
booking_code: z.string().nullish(),
})
.nullish(),
system: systemSchema.merge(
z.object({
created_at: z.string(),
@@ -134,27 +140,35 @@ export const campaignPageSchema = z
url: z.string(),
}),
})
.transform((data) => {
const blocks = data.campaign_page.blocks.map((block) => {
if (
block.__typename === CampaignPageEnum.ContentStack.blocks.HotelListing
) {
return {
...block,
hotel_listing: {
...block.hotel_listing,
hotelIds: data.campaign_page.included_hotels,
},
}
.transform(({ campaign_page, ...data }) => {
const { blocks, page_settings, included_hotels, ...campaignPageData } =
campaign_page
const bookingCode = page_settings?.booking_code || null
const mappedBlocks = blocks.map((block) => {
switch (block.__typename) {
case CampaignPageEnum.ContentStack.blocks.HotelListing:
return {
...block,
hotel_listing: {
...block.hotel_listing,
hotelIds: included_hotels,
bookingCode,
},
}
case CampaignPageEnum.ContentStack.blocks.CarouselCards:
return getCarouselCardsBlockWithBookingCodeLinks(block, bookingCode)
case CampaignPageEnum.ContentStack.blocks.Essentials:
case CampaignPageEnum.ContentStack.blocks.Accordion:
default:
return block
}
return block
})
return {
...data,
campaign_page: {
...data.campaign_page,
blocks: [...blocks],
...campaignPageData,
blocks: [...mappedBlocks],
},
}
})

View File

@@ -1,9 +1,12 @@
import { CampaignPageEnum } from "../../../types/campaignPage"
import {
CampaignPageEnum,
type CampaignPageRefs,
} from "../../../types/campaignPage"
import { generateTag, generateTagsFromSystem } from "../../../utils/generateTag"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { CampaignPageRefs } from "../../../types/campaignPage"
import type { CarouselCardsBlock } from "../../../types/campaignPage"
import type { System } from "../schemas/system"
export function generatePageTags(
@@ -43,3 +46,35 @@ export function getConnections({ campaign_page }: CampaignPageRefs) {
return connections
}
export function getCarouselCardsBlockWithBookingCodeLinks(
block: CarouselCardsBlock,
bookingCode: string | null
): CarouselCardsBlock {
if (!bookingCode) {
return block
}
const { link, cards, ...carousel_cards } = block.carousel_cards
return {
...block,
carousel_cards: {
...carousel_cards,
link: link
? {
...link,
href: `${link.href}?bookingCode=${bookingCode}`,
}
: undefined,
cards: cards.map(({ link, ...card }) => ({
...card,
link: link
? {
...link,
href: `${link.href}?bookingCode=${bookingCode}`,
}
: undefined,
})),
},
}
}

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import {
linkRefsUnionSchema,
linkUnionSchema,

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import {
contentCardRefSchema,
contentCardSchema,

View File

@@ -1,7 +1,7 @@
import { z } from "zod"
import { scriptedCardThemeEnum } from "../../../../enums/scriptedCard"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import {
CardsGridEnum,
CardsGridLayoutEnum,

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import {
contentCardRefSchema,
contentCardSchema,
@@ -66,6 +66,7 @@ const carouselCardGroupsNoFilterSchema = z
.filter((card): card is NonNullable<typeof card> => card !== null)
.map((card) => ({
...card,
filterId: "", // No filter for these cards
}))
return {
cards,

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { ContentEnum } from "../../../../types/content"
import {
accountPageSchema,

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { DynamicContentEnum } from "../../../../types/dynamicContent"
import {
linkRefsUnionSchema,

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
export const essentialsSchema = z.object({
essentials: z.object({

View File

@@ -1,7 +1,7 @@
import { z } from "zod"
import * as pageLinks from "../../../../routers/contentstack/schemas/pageLinks"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { tempImageVaultAssetSchema } from "../imageVault"
import { systemSchema } from "../system"
import { buttonSchema } from "./utils/buttonLinkSchema"

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { HotelPageEnum } from "../../../../types/hotelPageEnum"
import {
accordionItemsSchema,

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { Country } from "../../../../types/country"
export const locationFilterSchema = z

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { tempImageVaultAssetSchema } from "../imageVault"
import { buttonSchema } from "./utils/buttonLinkSchema"
import { linkConnectionRefsSchema } from "./utils/linkConnection"

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import {
linkRefsUnionSchema,
linkUnionSchema,

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
export const tableSchema = z.object({
typename: z

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { ContentEnum } from "../../../../types/content"
import {
linkRefsUnionSchema,

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { sysAssetSchema } from "./sysAsset"
export const textContentSchema = z.object({

View File

@@ -1,6 +1,6 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocks"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { UspGridEnum } from "../../../../types/uspGrid"
import {
linkRefsUnionSchema,

View File

@@ -1,21 +1,28 @@
export namespace BlocksEnums {
export const enum block {
Accordion = "Accordion",
CardGallery = "CardGallery",
CardsGrid = "CardsGrid",
CarouselCards = "CarouselCards",
Content = "Content",
DynamicContent = "DynamicContent",
FullWidthCampaign = "FullWidthCampaign",
CampaignOverviewPageHotelListing = "CampaignOverviewPageHotelListing",
CampaignPageHotelListing = "CampaignPageHotelListing",
ContentPageHotelListing = "ContentPageHotelListing",
JoinScandicFriends = "JoinScandicFriends",
Shortcuts = "Shortcuts",
Table = "Table",
TextCols = "TextCols",
TextContent = "TextContent",
UspGrid = "UspGrid",
Essentials = "Essentials",
}
}
import type { cardGallerySchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/cardGallery"
import type { teaserCardBlockSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/cards/teaserCard"
import type { cardsGridSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/cardsGrid"
import type { carouselCardsSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/carouselCards"
import type { contentSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/content"
import type { dynamicContentSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/dynamicContent"
import type { contentPageHotelListingSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/hotelListing"
import type { shortcutsSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/shortcuts"
import type { tableSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/table"
import type { textColsSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/textCols"
import type { uspGridSchema } from "@scandic-hotels/trpc/routers/contentstack/schemas/blocks/uspGrid"
import type { z } from "zod"
export interface TeaserCard extends z.output<typeof teaserCardBlockSchema> {}
export interface CardsGrid extends z.output<typeof cardsGridSchema> {}
export interface Content extends z.output<typeof contentSchema> {}
export interface DynamicContent extends z.output<typeof dynamicContentSchema> {}
export interface Shortcuts extends z.output<typeof shortcutsSchema> {}
export type Shortcut = Shortcuts["shortcuts"]
export interface TableBlock extends z.output<typeof tableSchema> {}
export type TableData = TableBlock["table"]
export interface TextCols extends z.output<typeof textColsSchema> {}
export interface UspGrid extends z.output<typeof uspGridSchema> {}
interface GetHotelListing
extends z.output<typeof contentPageHotelListingSchema> {}
export type HotelListing = GetHotelListing["hotel_listing"]
export interface CarouselCards extends z.output<typeof carouselCardsSchema> {}
export interface CardGallery extends z.output<typeof cardGallerySchema> {}

View File

@@ -0,0 +1,21 @@
export namespace BlocksEnums {
export const enum block {
Accordion = "Accordion",
CardGallery = "CardGallery",
CardsGrid = "CardsGrid",
CarouselCards = "CarouselCards",
Content = "Content",
DynamicContent = "DynamicContent",
FullWidthCampaign = "FullWidthCampaign",
CampaignOverviewPageHotelListing = "CampaignOverviewPageHotelListing",
CampaignPageHotelListing = "CampaignPageHotelListing",
ContentPageHotelListing = "ContentPageHotelListing",
JoinScandicFriends = "JoinScandicFriends",
Shortcuts = "Shortcuts",
Table = "Table",
TextCols = "TextCols",
TextContent = "TextContent",
UspGrid = "UspGrid",
Essentials = "Essentials",
}
}

View File

@@ -5,6 +5,7 @@ import type {
campaignPageSchema,
heroSchema,
} from "../routers/contentstack/campaignPage/output"
import type { carouselCardsSchema } from "../routers/contentstack/schemas/blocks/carouselCards"
import type { essentialsSchema } from "../routers/contentstack/schemas/blocks/essentials"
export namespace CampaignPageEnum {
@@ -31,6 +32,8 @@ export interface CampaignPageRefs
export type Block = CampaignPageData["blocks"][number]
export interface CarouselCardsBlock
extends z.output<typeof carouselCardsSchema> {}
export type EssentialsBlock = z.output<typeof essentialsSchema>["essentials"]
export type Hero = z.output<typeof heroSchema>