Merged in feat/rework-contentstack (pull request #3493)

Feat(SW-3708): refactor contentstack fetching (removing all refs) and cache invalidation

* Remove all REFS

* Revalidate correct language

* PR fixes

* PR fixes

* Throw when errors from contentstack api


Approved-by: Joakim Jäderberg
This commit is contained in:
Linus Flood
2026-01-27 12:38:36 +00:00
parent a5e214f783
commit 5fc93472f4
193 changed files with 489 additions and 9018 deletions
@@ -6,14 +6,8 @@ import { nullableStringValidator } from "@scandic-hotels/common/utils/zod/string
import { PromoCampaignPageEnum } from "../../../types/promoCampaignPage"
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
import {
accordionRefsSchema,
accordionSchema,
} from "../schemas/blocks/accordion"
import {
contentRefsSchema as blockContentRefsSchema,
contentSchema as blockContentSchema,
} from "../schemas/blocks/content"
import { accordionSchema } from "../schemas/blocks/accordion"
import { contentSchema as blockContentSchema } from "../schemas/blocks/content"
import { systemSchema } from "../schemas/system"
export const promoCampaignPageContent = z
@@ -96,30 +90,3 @@ export const promoCampaignPageSchema = z
},
}
})
/** REFS */
const promoCampaignPageBlockContentRefs = z
.object({
__typename: z.literal(PromoCampaignPageEnum.ContentStack.blocks.Content),
})
.merge(blockContentRefsSchema)
const promoCampaignPageAccordionRefs = z
.object({
__typename: z.literal(PromoCampaignPageEnum.ContentStack.blocks.Accordion),
})
.merge(accordionRefsSchema)
const promoCampaignPageBlockRefsItem = z.discriminatedUnion("__typename", [
promoCampaignPageAccordionRefs,
promoCampaignPageBlockContentRefs,
])
export const promoCampaignPageRefsSchema = z.object({
promo_campaign_page: z.object({
blocks: discriminatedUnionArray(
promoCampaignPageBlockRefsItem.options
).nullable(),
system: systemSchema,
}),
})
@@ -2,64 +2,20 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
import { router } from "../../.."
import { notFoundError } from "../../../errors"
import {
GetPromoCampaignPage,
GetPromoCampaignPageRefs,
} from "../../../graphql/Query/PromoCampaignPage/PromoCampaignPage.graphql"
import { GetPromoCampaignPage } from "../../../graphql/Query/PromoCampaignPage/PromoCampaignPage.graphql"
import { request } from "../../../graphql/request"
import { contentStackUidWithServiceProcedure } from "../../../procedures"
import { generateRefsResponseTag } from "../../../utils/generateTag"
import { promoCampaignPageRefsSchema, promoCampaignPageSchema } from "./output"
import { generatePageTags } from "./utils"
import { generateTag } from "../../../utils/generateTag"
import { promoCampaignPageSchema } from "./output"
import type {
GetPromoCampaignPageData,
GetPromoCampaignPageRefsData,
} from "../../../types/promoCampaignPage"
import type { GetPromoCampaignPageData } from "../../../types/promoCampaignPage"
import type { TrackingPageData } from "../../types"
export const promoCampaignPageQueryRouter = router({
get: contentStackUidWithServiceProcedure.query(async ({ ctx }) => {
const { lang, uid } = ctx
const getPromoCampaignPageRefsCounter = createCounter(
"trpc.contentstack.promoCampaignPage.get.refs"
)
const metricsGetPromoCampaignPageRefs =
getPromoCampaignPageRefsCounter.init({
lang,
uid,
})
metricsGetPromoCampaignPageRefs.start()
const refsResponse = await request<GetPromoCampaignPageRefsData>(
GetPromoCampaignPageRefs,
{ locale: lang, uid },
{
key: generateRefsResponseTag(lang, uid),
ttl: "max",
}
)
if (!refsResponse.data) {
metricsGetPromoCampaignPageRefs.noDataError()
throw notFoundError({
message: "GetPromoCampaignPageRefs returned no data",
errorDetails: { lang, uid },
})
}
const validatedRefsData = promoCampaignPageRefsSchema.safeParse(
refsResponse.data
)
if (!validatedRefsData.success) {
metricsGetPromoCampaignPageRefs.validationError(validatedRefsData.error)
return null
}
metricsGetPromoCampaignPageRefs.success()
const tags = generatePageTags(validatedRefsData.data, lang)
const cacheKey = generateTag(lang, uid)
const getPromoCampaignPageCounter = createCounter(
"trpc.contentstack.promoCampaignPage.get"
@@ -78,7 +34,7 @@ export const promoCampaignPageQueryRouter = router({
uid,
},
{
key: tags,
key: `${cacheKey}:promoCampaignPage`,
ttl: "max",
}
)
@@ -1,54 +0,0 @@
import {
PromoCampaignPageEnum,
type PromoCampaignPageRefs,
} from "../../../types/promoCampaignPage"
import {
generateTag,
generateTagsFromAssetSystem,
generateTagsFromSystem,
} from "../../../utils/generateTag"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { AssetSystem, System } from "../schemas/system"
export function generatePageTags(
validatedData: PromoCampaignPageRefs,
lang: Lang
): string[] {
const { connections, assetConnections } = getConnections(validatedData)
return [
generateTagsFromSystem(lang, connections),
generateTagsFromAssetSystem(assetConnections),
generateTag(lang, validatedData.promo_campaign_page.system.uid),
].flat()
}
export function getConnections({ promo_campaign_page }: PromoCampaignPageRefs) {
const connections: System["system"][] = [promo_campaign_page.system]
const assetConnections: AssetSystem[] = []
if (promo_campaign_page.blocks) {
promo_campaign_page.blocks.forEach((block) => {
switch (block.__typename) {
case PromoCampaignPageEnum.ContentStack.blocks.Accordion:
if (block.accordion.length) {
connections.push(...block.accordion.filter((c) => !!c))
}
break
case PromoCampaignPageEnum.ContentStack.blocks.Content:
if (block?.content?.length) {
block.content.forEach((contentBlock) => {
if ("system" in contentBlock) {
assetConnections.push(contentBlock)
} else {
connections.push(contentBlock)
}
})
}
break
}
})
}
return { connections, assetConnections }
}