Files
web/packages/trpc/lib/routers/contentstack/campaignPage/output.ts
Erik Tiekstra 270249c6c4 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
2025-07-04 10:15:01 +00:00

206 lines
5.4 KiB
TypeScript

import { z } from "zod"
import { CampaignPageEnum } from "../../../types/campaignPage"
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
import {
accordionRefsSchema,
accordionSchema,
} from "../schemas/blocks/accordion"
import {
carouselCardsRefsSchema,
carouselCardsSchema,
} from "../schemas/blocks/carouselCards"
import { essentialsBlockSchema } from "../schemas/blocks/essentials"
import { campaignPageHotelListingSchema } from "../schemas/blocks/hotelListing"
import { tempImageVaultAssetSchema } from "../schemas/imageVault"
import {
linkConnectionRefs,
linkConnectionSchema,
} from "../schemas/linkConnection"
import { systemSchema } from "../schemas/system"
import { getCarouselCardsBlockWithBookingCodeLinks } from "./utils"
const campaignPageEssentials = z
.object({
__typename: z.literal(CampaignPageEnum.ContentStack.blocks.Essentials),
})
.merge(essentialsBlockSchema)
const campaignPageCarouselCards = z
.object({
__typename: z.literal(CampaignPageEnum.ContentStack.blocks.CarouselCards),
})
.merge(carouselCardsSchema)
export const campaignPageAccordion = z
.object({
__typename: z.literal(CampaignPageEnum.ContentStack.blocks.Accordion),
})
.merge(accordionSchema)
export const campaignPageHotelListing = z
.object({
__typename: z.literal(CampaignPageEnum.ContentStack.blocks.HotelListing),
})
.merge(campaignPageHotelListingSchema)
export const blocksSchema = z.discriminatedUnion("__typename", [
campaignPageEssentials,
campaignPageCarouselCards,
campaignPageAccordion,
campaignPageHotelListing,
])
export const heroSchema = z.object({
image: tempImageVaultAssetSchema,
heading: z.string(),
theme: z.enum(["Peach", "Burgundy"]).default("Peach"),
benefits: z
.array(z.string())
.nullish()
.transform((data) => data || []),
rate_text: z
.object({
bold_text: z.string().nullish(),
text: z.string().nullish(),
})
.nullish(),
button: z
.intersection(z.object({ cta: z.string() }), linkConnectionSchema)
.transform((data) => {
if (!data.link) {
return null
}
return {
cta: data.cta,
url: data.link?.url || "",
}
}),
})
export const includedHotelsSchema = z
.object({
list_1Connection: z.object({
edges: z.array(
z.object({
node: z.object({
hotel_page_id: z.string(),
}),
})
),
}),
list_2Connection: z.object({
edges: z.array(
z.object({
node: z.object({
hotel_page_id: z.string(),
}),
})
),
}),
})
.transform((data) => {
const list1HotelIds = data.list_1Connection.edges
.map((edge) => edge.node.hotel_page_id)
.filter(Boolean)
const list2HotelIds = data.list_2Connection.edges
.map((edge) => edge.node.hotel_page_id)
.filter(Boolean)
return [...new Set([...list1HotelIds, ...list2HotelIds])]
})
export const campaignPageSchema = z
.object({
campaign_page: z.object({
title: z.string(),
hero: heroSchema,
heading: z.string(),
subheading: z.string().nullish(),
included_hotels: includedHotelsSchema,
preamble: z.object({
is_two_columns: z.boolean().default(false),
first_column: z.string(),
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(),
updated_at: z.string(),
})
),
}),
trackingProps: z.object({
url: z.string(),
}),
})
.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 {
...data,
campaign_page: {
...campaignPageData,
blocks: [...mappedBlocks],
},
}
})
/** REFS */
const campaignPageCarouselCardsRef = z
.object({
__typename: z.literal(CampaignPageEnum.ContentStack.blocks.CarouselCards),
})
.merge(carouselCardsRefsSchema)
const campaignPageAccordionRefs = z
.object({
__typename: z.literal(CampaignPageEnum.ContentStack.blocks.Accordion),
})
.merge(accordionRefsSchema)
const campaignPageBlockRefsItem = z.discriminatedUnion("__typename", [
campaignPageCarouselCardsRef,
campaignPageAccordionRefs,
])
const heroRefsSchema = z.object({
button: linkConnectionRefs,
})
export const campaignPageRefsSchema = z.object({
campaign_page: z.object({
hero: heroRefsSchema,
blocks: discriminatedUnionArray(
campaignPageBlockRefsItem.options
).nullable(),
system: systemSchema,
}),
})