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:
@@ -3,14 +3,9 @@ import { z } from "zod"
|
||||
import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/imageVault"
|
||||
import { IconName } from "@scandic-hotels/design-system/Icons/iconName"
|
||||
|
||||
import {
|
||||
linkConnectionRefs,
|
||||
linkConnectionSchema,
|
||||
} from "../schemas/linkConnection"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
import { linkConnectionSchema } from "../schemas/linkConnection"
|
||||
|
||||
export type UsePointsModalData = z.output<typeof usePointsModalSchema>
|
||||
export type UsePointsModalRefsData = z.output<typeof usePointsModalRefsSchema>
|
||||
type LinkGroupItem = z.infer<typeof linkGroupItemSchema>
|
||||
|
||||
const linkGroupItemSchema = z.intersection(
|
||||
@@ -57,16 +52,3 @@ export const usePointsModalSchema = z.object({
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
|
||||
export const usePointsModalRefsSchema = z.object({
|
||||
all_usepointsmodal: z
|
||||
.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
link_group: z.array(linkConnectionRefs),
|
||||
system: systemSchema,
|
||||
})
|
||||
),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
|
||||
@@ -2,66 +2,15 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetUsePointsModal,
|
||||
GetUsePointsModalRefs,
|
||||
} from "../../../graphql/Query/UsePointsModal.graphql"
|
||||
import { GetUsePointsModal } from "../../../graphql/Query/UsePointsModal.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentstackBaseProcedure } from "../../../procedures"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTagsFromSystem,
|
||||
} from "../../../utils/generateTag"
|
||||
import {
|
||||
type UsePointsModalData,
|
||||
type UsePointsModalRefsData,
|
||||
usePointsModalRefsSchema,
|
||||
usePointsModalSchema,
|
||||
} from "./output"
|
||||
import { getConnections } from "./utils"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { type UsePointsModalData, usePointsModalSchema } from "./output"
|
||||
|
||||
export const usePointsModalQueryRouter = router({
|
||||
get: contentstackBaseProcedure.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
const getRefsCounter = createCounter(
|
||||
"trpc.contentstack.usePointsModal.get.refs"
|
||||
)
|
||||
const metricsRefs = getRefsCounter.init({
|
||||
lang,
|
||||
uid,
|
||||
})
|
||||
|
||||
metricsRefs.start()
|
||||
const refsTag = generateRefsResponseTag(lang, "usepointsmodal")
|
||||
|
||||
const variables = { locale: lang }
|
||||
const refsResponse = await request<UsePointsModalRefsData>(
|
||||
GetUsePointsModalRefs,
|
||||
variables,
|
||||
{
|
||||
key: refsTag,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
if (!refsResponse.data) {
|
||||
metricsRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetUsePointsModalRefs returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedRefsData = usePointsModalRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
|
||||
if (!validatedRefsData.success) {
|
||||
metricsRefs.validationError(validatedRefsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsRefs.success()
|
||||
|
||||
const getCounter = createCounter("trpc.contentstack.usePointsModal.get")
|
||||
|
||||
@@ -71,18 +20,13 @@ export const usePointsModalQueryRouter = router({
|
||||
})
|
||||
metrics.start()
|
||||
|
||||
const connections = getConnections(validatedRefsData.data)
|
||||
|
||||
const tags = [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, "usepointsmodal"),
|
||||
].flat()
|
||||
const variables = { locale: lang }
|
||||
|
||||
const response = await request<UsePointsModalData>(
|
||||
GetUsePointsModal,
|
||||
variables,
|
||||
{
|
||||
key: tags,
|
||||
key: generateTag(lang, "usepointsmodal"),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { System } from "../schemas/system"
|
||||
import type { UsePointsModalRefsData } from "./output"
|
||||
|
||||
export function getConnections({ all_usepointsmodal }: UsePointsModalRefsData) {
|
||||
const connections: System["system"][] = all_usepointsmodal?.items?.[0]
|
||||
? [all_usepointsmodal?.items?.[0]?.system]
|
||||
: []
|
||||
|
||||
if (all_usepointsmodal && all_usepointsmodal.items) {
|
||||
all_usepointsmodal?.items.forEach((item) => {
|
||||
item.link_group.forEach((link) => {
|
||||
link.link?.uid && connections.push(link.link)
|
||||
})
|
||||
})
|
||||
}
|
||||
return connections
|
||||
}
|
||||
@@ -4,18 +4,9 @@ import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/i
|
||||
|
||||
import { AccountPageEnum } from "../../../types/accountPageEnum"
|
||||
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
accordionRefsSchema,
|
||||
accordionSchema,
|
||||
} from "../schemas/blocks/accordion"
|
||||
import {
|
||||
dynamicContentRefsSchema,
|
||||
dynamicContentSchema,
|
||||
} from "../schemas/blocks/dynamicContent"
|
||||
import {
|
||||
shortcutsRefsSchema,
|
||||
shortcutsSchema,
|
||||
} from "../schemas/blocks/shortcuts"
|
||||
import { accordionSchema } from "../schemas/blocks/accordion"
|
||||
import { dynamicContentSchema } from "../schemas/blocks/dynamicContent"
|
||||
import { shortcutsSchema } from "../schemas/blocks/shortcuts"
|
||||
import { textContentSchema } from "../schemas/blocks/textContent"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
@@ -73,37 +64,3 @@ export const accountPageSchema = z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
const accountPageAccordionRefs = z
|
||||
.object({
|
||||
__typename: z.literal(AccountPageEnum.ContentStack.blocks.Accordion),
|
||||
})
|
||||
.merge(accordionRefsSchema)
|
||||
|
||||
const accountPageDynamicContentRefs = z
|
||||
.object({
|
||||
__typename: z.literal(AccountPageEnum.ContentStack.blocks.DynamicContent),
|
||||
})
|
||||
.merge(dynamicContentRefsSchema)
|
||||
|
||||
const accountPageShortcutsRefs = z
|
||||
.object({
|
||||
__typename: z.literal(AccountPageEnum.ContentStack.blocks.ShortCuts),
|
||||
})
|
||||
.merge(shortcutsRefsSchema)
|
||||
|
||||
const accountPageContentItemRefs = z.discriminatedUnion("__typename", [
|
||||
z.object({
|
||||
__typename: z.literal(AccountPageEnum.ContentStack.blocks.TextContent),
|
||||
}),
|
||||
accountPageAccordionRefs,
|
||||
accountPageDynamicContentRefs,
|
||||
accountPageShortcutsRefs,
|
||||
])
|
||||
|
||||
export const accountPageRefsSchema = z.object({
|
||||
account_page: z.object({
|
||||
content: discriminatedUnionArray(accountPageContentItemRefs.options),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,82 +2,31 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetAccountPage,
|
||||
GetAccountPageRefs,
|
||||
} from "../../../graphql/Query/AccountPage/AccountPage.graphql"
|
||||
import { GetAccountPage } from "../../../graphql/Query/AccountPage/AccountPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTagsFromSystem,
|
||||
} from "../../../utils/generateTag"
|
||||
import { accountPageRefsSchema, accountPageSchema } from "./output"
|
||||
import { getConnections } from "./utils"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { accountPageSchema } from "./output"
|
||||
|
||||
import type {
|
||||
GetAccountPageRefsSchema,
|
||||
GetAccountPageSchema,
|
||||
} from "../../../types/accountPage"
|
||||
import type { GetAccountPageSchema } from "../../../types/accountPage"
|
||||
import type { TrackingPageData } from "../../types"
|
||||
|
||||
export const accountPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const getAccountPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.accountPage.get.refs"
|
||||
)
|
||||
const metricsRefs = getAccountPageRefsCounter.init({ lang, uid })
|
||||
metricsRefs.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const refsResponse = await request<GetAccountPageRefsSchema>(
|
||||
GetAccountPageRefs,
|
||||
variables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, uid),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
metricsRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetAccountPageRefs returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedAccountPageRefs = accountPageRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
if (!validatedAccountPageRefs.success) {
|
||||
metricsRefs.validationError(validatedAccountPageRefs.error)
|
||||
return null
|
||||
}
|
||||
|
||||
const connections = getConnections(validatedAccountPageRefs.data)
|
||||
|
||||
const tags = [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, validatedAccountPageRefs.data.account_page.system.uid),
|
||||
].flat()
|
||||
|
||||
metricsRefs.success()
|
||||
|
||||
const getAccountPageCounter = createCounter(
|
||||
"trpc.contentstack.accountPage.get"
|
||||
)
|
||||
const metrics = getAccountPageCounter.init({ lang, uid })
|
||||
metrics.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const response = await request<GetAccountPageSchema>(
|
||||
GetAccountPage,
|
||||
variables,
|
||||
{
|
||||
key: tags,
|
||||
key: generateTag(lang, uid),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { AccountPageEnum } from "../../../types/accountPageEnum"
|
||||
|
||||
import type { AccountPageRefs } from "../../../types/accountPage"
|
||||
import type { System } from "../schemas/system"
|
||||
|
||||
export function getConnections({ account_page }: AccountPageRefs) {
|
||||
const connections: System["system"][] = [account_page.system]
|
||||
|
||||
if (account_page.content) {
|
||||
account_page.content.forEach((block) => {
|
||||
switch (block.__typename) {
|
||||
case AccountPageEnum.ContentStack.blocks.ShortCuts: {
|
||||
if (block.shortcuts.shortcuts.length) {
|
||||
connections.push(...block.shortcuts.shortcuts.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
}
|
||||
case AccountPageEnum.ContentStack.blocks.DynamicContent: {
|
||||
if (block.dynamic_content.link) {
|
||||
connections.push(block.dynamic_content.link)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
@@ -11,20 +11,14 @@ import { nullableStringValidator } from "@scandic-hotels/common/utils/zod/string
|
||||
|
||||
import { discriminatedUnion } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
infoCardBlockRefsSchema,
|
||||
infoCardBlockSchema,
|
||||
transformCardBlockRefs,
|
||||
transformInfoCardBlock,
|
||||
} from "../schemas/blocks/cardsGrid"
|
||||
import { linkConnectionRefsSchema } from "../schemas/blocks/utils/linkConnection"
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
rawLinkUnionSchema,
|
||||
transformPageLink,
|
||||
transformPageLinkRef,
|
||||
} from "../schemas/pageLinks"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
// Help me write this zod schema based on the type ContactConfig
|
||||
export const validateContactConfigSchema = z.object({
|
||||
@@ -218,150 +212,6 @@ export const validateFooterConfigSchema = z
|
||||
}
|
||||
})
|
||||
|
||||
const pageConnectionRefs = z.object({
|
||||
edges: z
|
||||
.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
)
|
||||
.max(1),
|
||||
})
|
||||
|
||||
export const validateFooterRefConfigSchema = z.object({
|
||||
all_footer: z.object({
|
||||
items: z
|
||||
.array(
|
||||
z.object({
|
||||
main_links: z
|
||||
.array(
|
||||
z.object({
|
||||
pageConnection: pageConnectionRefs,
|
||||
})
|
||||
)
|
||||
.nullable(),
|
||||
secondary_links: z
|
||||
.array(
|
||||
z.object({
|
||||
links: z.array(
|
||||
z.object({
|
||||
pageConnection: pageConnectionRefs,
|
||||
})
|
||||
),
|
||||
})
|
||||
)
|
||||
.nullable(),
|
||||
tertiary_links: z
|
||||
.array(
|
||||
z.object({
|
||||
pageConnection: pageConnectionRefs,
|
||||
})
|
||||
)
|
||||
.nullable(),
|
||||
system: systemSchema,
|
||||
})
|
||||
)
|
||||
.length(1),
|
||||
}),
|
||||
})
|
||||
|
||||
/**
|
||||
* New Header Validation
|
||||
*/
|
||||
|
||||
const linkRefsSchema = z
|
||||
.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (data.linkConnection.edges.length) {
|
||||
const link = transformPageLinkRef(data.linkConnection.edges[0].node)
|
||||
if (link) {
|
||||
return {
|
||||
link,
|
||||
}
|
||||
}
|
||||
}
|
||||
return { link: null }
|
||||
})
|
||||
|
||||
const menuItemsRefsSchema = z.intersection(
|
||||
linkRefsSchema,
|
||||
z
|
||||
.object({
|
||||
cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: infoCardBlockRefsSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
see_all_link: linkRefsSchema,
|
||||
submenu: z.array(
|
||||
z.object({
|
||||
links: z.array(linkRefsSchema),
|
||||
})
|
||||
),
|
||||
})
|
||||
.transform((data) => {
|
||||
let card = null
|
||||
if (data.cardConnection.edges.length) {
|
||||
card = transformCardBlockRefs(data.cardConnection.edges[0].node)
|
||||
}
|
||||
|
||||
return {
|
||||
card,
|
||||
see_all_link: data.see_all_link,
|
||||
submenu: data.submenu,
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const topLinkRefsSchema = z.object({
|
||||
logged_in: linkRefsSchema.nullable(),
|
||||
logged_out: linkRefsSchema.nullable(),
|
||||
})
|
||||
|
||||
export const headerRefsSchema = z
|
||||
.object({
|
||||
all_header: z.object({
|
||||
items: z
|
||||
.array(
|
||||
z.object({
|
||||
menu_items: z.array(menuItemsRefsSchema),
|
||||
system: systemSchema,
|
||||
top_link: topLinkRefsSchema,
|
||||
})
|
||||
)
|
||||
.max(1),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (!data.all_header.items.length) {
|
||||
logger.error(`Zod Error - No header returned in refs request`)
|
||||
throw new ZodError([
|
||||
{
|
||||
code: ZodIssueCode.custom,
|
||||
fatal: true,
|
||||
message: "No header returned (Refs)",
|
||||
path: ["all_header.items"],
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
return {
|
||||
header: data.all_header.items[0],
|
||||
}
|
||||
})
|
||||
|
||||
const internalOrExternalLinkSchema = z
|
||||
.object({
|
||||
is_contentstack_link: z.boolean().nullish(),
|
||||
@@ -687,57 +537,6 @@ export const siteConfigSchema = z
|
||||
}
|
||||
})
|
||||
|
||||
const sidepeekContentRefSchema = z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const alertConnectionRefSchema = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
link: linkRefsSchema,
|
||||
sidepeek_content: sidepeekContentRefSchema,
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
),
|
||||
visible_on: z.array(z.string()).nullish().default([]),
|
||||
})
|
||||
|
||||
export const siteConfigRefSchema = z.object({
|
||||
all_site_config: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
sitewide_alert: z
|
||||
.object({
|
||||
alerts: z
|
||||
.array(
|
||||
z.object({
|
||||
alertConnection: alertConnectionRefSchema,
|
||||
})
|
||||
)
|
||||
.nullable(),
|
||||
})
|
||||
.transform((data) => {
|
||||
const sitewideAlertWeb = data.alerts?.find((alert) =>
|
||||
alert.alertConnection.visible_on?.includes(AlertVisibleOnEnum.WEB)
|
||||
)
|
||||
return { alert: sitewideAlertWeb || null }
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
const bannerSchema = z
|
||||
.object({
|
||||
tag: z.string(),
|
||||
@@ -762,20 +561,6 @@ const bannerSchema = z
|
||||
}
|
||||
})
|
||||
|
||||
const bannerRefSchema = z
|
||||
.object({
|
||||
link: linkConnectionRefsSchema,
|
||||
visible_on: z.array(z.string()).nullish().default([]),
|
||||
system: systemSchema,
|
||||
})
|
||||
.transform(({ link, visible_on, system }) => {
|
||||
return {
|
||||
linkSystem: link,
|
||||
visible_on,
|
||||
system,
|
||||
}
|
||||
})
|
||||
|
||||
export const sitewideCampaignBannerSchema = z
|
||||
.object({
|
||||
all_sitewide_campaign_banner: z.object({
|
||||
@@ -806,29 +591,3 @@ export const sitewideCampaignBannerSchema = z
|
||||
|
||||
return sitewideCampaignBannerWeb?.node ?? null
|
||||
})
|
||||
|
||||
export const sitewideCampaignBannerRefSchema = z.object({
|
||||
all_sitewide_campaign_banner: z
|
||||
.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
bannerConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: bannerRefSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
),
|
||||
})
|
||||
.transform((data) => {
|
||||
const webBanner = data.items.find((item) => {
|
||||
const bannerNode = item.bannerConnection.edges[0]?.node
|
||||
return bannerNode?.visible_on?.includes(AlertVisibleOnEnum.WEB)
|
||||
})
|
||||
|
||||
return webBanner ?? null
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -5,57 +5,31 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import { GetContactConfig } from "../../../graphql/Query/ContactConfig.graphql"
|
||||
import { GetFooter, GetFooterRef } from "../../../graphql/Query/Footer.graphql"
|
||||
import { GetHeader, GetHeaderRef } from "../../../graphql/Query/Header.graphql"
|
||||
import {
|
||||
GetSiteConfig,
|
||||
GetSiteConfigRef,
|
||||
} from "../../../graphql/Query/SiteConfig.graphql"
|
||||
import {
|
||||
GetSitewideCampaignBanner,
|
||||
GetSitewideCampaignBannerRef,
|
||||
} from "../../../graphql/Query/SitewideCampaignBanner.graphql"
|
||||
import { GetFooter } from "../../../graphql/Query/Footer.graphql"
|
||||
import { GetHeader } from "../../../graphql/Query/Header.graphql"
|
||||
import { GetSiteConfig } from "../../../graphql/Query/SiteConfig.graphql"
|
||||
import { GetSitewideCampaignBanner } from "../../../graphql/Query/SitewideCampaignBanner.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentstackBaseProcedure } from "../../../procedures"
|
||||
import { langInput } from "../../../utils"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTags,
|
||||
generateTagsFromSystem,
|
||||
} from "../../../utils/generateTag"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import {
|
||||
type ContactConfigData,
|
||||
headerRefsSchema,
|
||||
headerSchema,
|
||||
siteConfigRefSchema,
|
||||
siteConfigSchema,
|
||||
sitewideCampaignBannerRefSchema,
|
||||
sitewideCampaignBannerSchema,
|
||||
validateContactConfigSchema,
|
||||
validateFooterConfigSchema,
|
||||
validateFooterRefConfigSchema,
|
||||
} from "./output"
|
||||
import {
|
||||
getAlertPhoneContactData,
|
||||
getConnections,
|
||||
getFooterConnections,
|
||||
getSiteConfigConnections,
|
||||
getSitewideCampaignBannerConnections,
|
||||
} from "./utils"
|
||||
import { getAlertPhoneContactData } from "./utils"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type { FooterDataRaw, FooterRefDataRaw } from "../../../types/footer"
|
||||
import type {
|
||||
GetHeader as GetHeaderData,
|
||||
GetHeaderRefs,
|
||||
} from "../../../types/header"
|
||||
import type { FooterDataRaw } from "../../../types/footer"
|
||||
import type { GetHeader as GetHeaderData } from "../../../types/header"
|
||||
import type {
|
||||
GetSiteConfigData,
|
||||
GetSiteConfigRefData,
|
||||
GetSitewideCampaignBannerData,
|
||||
GetSitewideCampaignBannerRefData,
|
||||
} from "../../../types/siteConfig"
|
||||
|
||||
const getContactConfig = cache(async (lang: Lang) => {
|
||||
@@ -103,51 +77,13 @@ export const baseQueryRouter = router({
|
||||
}),
|
||||
header: contentstackBaseProcedure.query(async ({ ctx }) => {
|
||||
const { lang } = ctx
|
||||
|
||||
const getHeaderRefsCounter = createCounter(
|
||||
"trpc.contentstack.header.get.refs"
|
||||
)
|
||||
const metricsGetHeaderRefs = getHeaderRefsCounter.init({ lang })
|
||||
|
||||
metricsGetHeaderRefs.start()
|
||||
|
||||
const variables = { locale: lang }
|
||||
const responseRef = await request<GetHeaderRefs>(GetHeaderRef, variables, {
|
||||
key: generateRefsResponseTag(lang, "header"),
|
||||
ttl: "max",
|
||||
})
|
||||
|
||||
if (!responseRef.data) {
|
||||
metricsGetHeaderRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetHeaderRef returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedHeaderRefs = headerRefsSchema.safeParse(responseRef.data)
|
||||
|
||||
if (!validatedHeaderRefs.success) {
|
||||
metricsGetHeaderRefs.validationError(validatedHeaderRefs.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetHeaderRefs.success()
|
||||
|
||||
const connections = getConnections(validatedHeaderRefs.data)
|
||||
|
||||
const getHeaderCounter = createCounter("trpc.contentstack.header.get")
|
||||
const metricsGetHeader = getHeaderCounter.init({ lang })
|
||||
|
||||
metricsGetHeader.start()
|
||||
|
||||
const tags = [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, validatedHeaderRefs.data.header.system.uid),
|
||||
].flat()
|
||||
|
||||
const variables = { locale: lang }
|
||||
const response = await request<GetHeaderData>(GetHeader, variables, {
|
||||
key: tags,
|
||||
key: generateTag(lang, "header"),
|
||||
ttl: "max",
|
||||
})
|
||||
|
||||
@@ -168,64 +104,17 @@ export const baseQueryRouter = router({
|
||||
|
||||
metricsGetHeader.success()
|
||||
|
||||
return {
|
||||
data: validatedHeaderConfig.data.header,
|
||||
}
|
||||
return { data: validatedHeaderConfig.data.header }
|
||||
}),
|
||||
footer: contentstackBaseProcedure.query(async ({ ctx }) => {
|
||||
const { lang } = ctx
|
||||
|
||||
const getFooterRefsCounter = createCounter(
|
||||
"trpc.contentstack.footer.get.refs"
|
||||
)
|
||||
const metricsGetFooterRefs = getFooterRefsCounter.init({ lang })
|
||||
|
||||
metricsGetFooterRefs.start()
|
||||
|
||||
const variables = { locale: lang }
|
||||
const responseRef = await request<FooterRefDataRaw>(
|
||||
GetFooterRef,
|
||||
variables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, "footer"),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!responseRef.data) {
|
||||
metricsGetFooterRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetFooterRef returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedFooterRefs = validateFooterRefConfigSchema.safeParse(
|
||||
responseRef.data
|
||||
)
|
||||
|
||||
if (!validatedFooterRefs.success) {
|
||||
metricsGetFooterRefs.validationError(validatedFooterRefs.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetFooterRefs.success()
|
||||
|
||||
const connections = getFooterConnections(validatedFooterRefs.data)
|
||||
const footerUID = responseRef.data.all_footer.items[0].system.uid
|
||||
|
||||
const getFooterCounter = createCounter("trpc.contentstack.footer.get")
|
||||
const metricsGetFooter = getFooterCounter.init({ lang })
|
||||
|
||||
metricsGetFooter.start()
|
||||
|
||||
const tags = [
|
||||
generateTags(lang, connections),
|
||||
generateTag(lang, footerUID),
|
||||
].flat()
|
||||
|
||||
const variables = { locale: lang }
|
||||
const response = await request<FooterDataRaw>(GetFooter, variables, {
|
||||
key: tags,
|
||||
key: generateTag(lang, "footer"),
|
||||
ttl: "max",
|
||||
})
|
||||
|
||||
@@ -256,52 +145,6 @@ export const baseQueryRouter = router({
|
||||
.query(async ({ input, ctx }) => {
|
||||
const lang = input.lang ?? ctx.lang
|
||||
|
||||
const getSitewideCampaignBannerRefsCounter = createCounter(
|
||||
"trpc.contentstack.sitewideCampaignBanner.get.refs"
|
||||
)
|
||||
const metricsGetSitewideCampaignBannerRefs =
|
||||
getSitewideCampaignBannerRefsCounter.init({
|
||||
lang,
|
||||
})
|
||||
|
||||
metricsGetSitewideCampaignBannerRefs.start()
|
||||
|
||||
const refVariables = { locale: lang }
|
||||
const responseRef = await request<GetSitewideCampaignBannerRefData>(
|
||||
GetSitewideCampaignBannerRef,
|
||||
refVariables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, "sitewide_campaign_banner"),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!responseRef.data) {
|
||||
metricsGetSitewideCampaignBannerRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetSitewideCampaignBannerRef returned no data",
|
||||
errorDetails: refVariables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedSitewideCampaignBannerRef =
|
||||
sitewideCampaignBannerRefSchema.safeParse(responseRef.data)
|
||||
|
||||
if (!validatedSitewideCampaignBannerRef.success) {
|
||||
metricsGetSitewideCampaignBannerRefs.validationError(
|
||||
validatedSitewideCampaignBannerRef.error
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const connections = getSitewideCampaignBannerConnections(
|
||||
validatedSitewideCampaignBannerRef.data
|
||||
)
|
||||
|
||||
const tags = [generateTagsFromSystem(lang, connections)].flat()
|
||||
|
||||
metricsGetSitewideCampaignBannerRefs.success()
|
||||
|
||||
const getSitewideCampaignBannerCounter = createCounter(
|
||||
"trpc.contentstack.sitewideCampaignBanner.get"
|
||||
)
|
||||
@@ -317,7 +160,7 @@ export const baseQueryRouter = router({
|
||||
await request<GetSitewideCampaignBannerData>(
|
||||
GetSitewideCampaignBanner,
|
||||
variables,
|
||||
{ key: tags, ttl: "max" }
|
||||
{ key: generateTag(lang, "sitewide_campaign_banner"), ttl: "max" }
|
||||
)
|
||||
|
||||
if (!sitewideCampaignBannerResponse.data) {
|
||||
@@ -351,52 +194,6 @@ export const baseQueryRouter = router({
|
||||
.query(async ({ input, ctx }) => {
|
||||
const lang = input.lang ?? ctx.lang
|
||||
|
||||
const getSiteConfigRefsCounter = createCounter(
|
||||
"trpc.contentstack.siteConfig.get.refs"
|
||||
)
|
||||
const metricsGetSiteConfigRefs = getSiteConfigRefsCounter.init({ lang })
|
||||
|
||||
metricsGetSiteConfigRefs.start()
|
||||
|
||||
const refVariables = {
|
||||
locale: lang,
|
||||
}
|
||||
const responseRef = await request<GetSiteConfigRefData>(
|
||||
GetSiteConfigRef,
|
||||
refVariables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, "site_config"),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!responseRef.data) {
|
||||
metricsGetSiteConfigRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "SiteConfigRefs returned no data",
|
||||
errorDetails: refVariables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedSiteConfigRef = siteConfigRefSchema.safeParse(
|
||||
responseRef.data
|
||||
)
|
||||
|
||||
if (!validatedSiteConfigRef.success) {
|
||||
metricsGetSiteConfigRefs.validationError(validatedSiteConfigRef.error)
|
||||
return null
|
||||
}
|
||||
|
||||
const connections = getSiteConfigConnections(validatedSiteConfigRef.data)
|
||||
const siteConfigUid = responseRef.data.all_site_config.items[0].system.uid
|
||||
|
||||
const tags = [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, siteConfigUid),
|
||||
].flat()
|
||||
|
||||
metricsGetSiteConfigRefs.success()
|
||||
|
||||
const getSiteConfigCounter = createCounter(
|
||||
"trpc.contentstack.siteConfig.get"
|
||||
)
|
||||
@@ -407,7 +204,7 @@ export const baseQueryRouter = router({
|
||||
const variables = { locale: lang }
|
||||
const [siteConfigResponse, contactConfig] = await Promise.all([
|
||||
request<GetSiteConfigData>(GetSiteConfig, variables, {
|
||||
key: tags,
|
||||
key: generateTag(lang, "site_config"),
|
||||
ttl: "max",
|
||||
}),
|
||||
getContactConfig(lang),
|
||||
|
||||
@@ -5,112 +5,9 @@ import { logger } from "@scandic-hotels/common/logger"
|
||||
|
||||
import { getValueFromContactConfig } from "../../../utils/contactConfig"
|
||||
|
||||
import type { Edges } from "../../../types/edges"
|
||||
import type { FooterRefDataRaw } from "../../../types/footer"
|
||||
import type { HeaderRefs } from "../../../types/header"
|
||||
import type { NodeRefs } from "../../../types/refs"
|
||||
import type {
|
||||
AlertOutput,
|
||||
GetSiteConfigRefData,
|
||||
GetSitewideCampaignBannerRefData,
|
||||
} from "../../../types/siteConfig"
|
||||
import type { System } from "../schemas/system"
|
||||
import type { AlertOutput } from "../../../types/siteConfig"
|
||||
import type { ContactConfig } from "./output"
|
||||
|
||||
export function getConnections({ header }: HeaderRefs) {
|
||||
const connections: System["system"][] = [header.system]
|
||||
|
||||
if (header.top_link) {
|
||||
if (header.top_link.logged_in?.link) {
|
||||
connections.push(header.top_link.logged_in.link)
|
||||
}
|
||||
if (header.top_link.logged_out?.link) {
|
||||
connections.push(header.top_link.logged_out.link)
|
||||
}
|
||||
}
|
||||
|
||||
if (header.menu_items.length) {
|
||||
header.menu_items.forEach((menuItem) => {
|
||||
if (menuItem.card) {
|
||||
connections.push(...menuItem.card)
|
||||
}
|
||||
if (menuItem.link) {
|
||||
connections.push(menuItem.link)
|
||||
}
|
||||
if (menuItem.see_all_link?.link) {
|
||||
connections.push(menuItem.see_all_link.link)
|
||||
}
|
||||
if (menuItem.submenu.length) {
|
||||
menuItem.submenu.forEach((subMenuItem) => {
|
||||
if (subMenuItem.links.length) {
|
||||
subMenuItem.links.forEach((link) => {
|
||||
if (link?.link) {
|
||||
connections.push(link.link)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
export function getFooterConnections(refs: FooterRefDataRaw) {
|
||||
const connections: Edges<NodeRefs>[] = []
|
||||
const footerData = refs.all_footer.items[0]
|
||||
const mainLinks = footerData.main_links
|
||||
const secondaryLinks = footerData.secondary_links
|
||||
const tertiaryLinks = footerData.tertiary_links
|
||||
if (mainLinks) {
|
||||
mainLinks.forEach(({ pageConnection }) => {
|
||||
connections.push(pageConnection)
|
||||
})
|
||||
}
|
||||
secondaryLinks?.forEach(({ links }) => {
|
||||
if (links) {
|
||||
links.forEach(({ pageConnection }) => {
|
||||
connections.push(pageConnection)
|
||||
})
|
||||
}
|
||||
})
|
||||
if (tertiaryLinks) {
|
||||
tertiaryLinks.forEach(({ pageConnection }) => {
|
||||
connections.push(pageConnection)
|
||||
})
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
export function getSiteConfigConnections(refs: GetSiteConfigRefData) {
|
||||
const siteConfigData = refs.all_site_config.items[0]
|
||||
const connections: System["system"][] = []
|
||||
|
||||
if (!siteConfigData.sitewide_alert.alert) return connections
|
||||
|
||||
const alertConnection = siteConfigData.sitewide_alert.alert.alertConnection
|
||||
|
||||
alertConnection.edges.forEach(({ node }) => {
|
||||
connections.push(node.system)
|
||||
|
||||
const link = node.link.link
|
||||
if (link) {
|
||||
connections.push(link)
|
||||
}
|
||||
node.sidepeek_content.content.embedded_itemsConnection.edges.forEach(
|
||||
({ node }) => {
|
||||
if (node.system) {
|
||||
connections.push(node.system)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
export function getAlertPhoneContactData(
|
||||
alert: AlertOutput,
|
||||
contactConfig: ContactConfig
|
||||
@@ -139,21 +36,3 @@ export const safeUnion = <T extends z.ZodTypeAny>(schema: T) =>
|
||||
return null
|
||||
}
|
||||
}, schema)
|
||||
|
||||
export function getSitewideCampaignBannerConnections(
|
||||
refs: GetSitewideCampaignBannerRefData
|
||||
) {
|
||||
const system = refs.all_sitewide_campaign_banner?.system
|
||||
const banner =
|
||||
refs.all_sitewide_campaign_banner?.bannerConnection.edges[0]?.node
|
||||
const connections: System["system"][] = []
|
||||
|
||||
if (system) {
|
||||
connections.push(system)
|
||||
}
|
||||
if (banner?.system) {
|
||||
connections.push(banner.system)
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
@@ -5,28 +5,6 @@ import { removeMultipleSlashes } from "@scandic-hotels/common/utils/url"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
import { homeBreadcrumbs } from "./utils"
|
||||
|
||||
export const breadcrumbsRefsSchema = z.object({
|
||||
web: z
|
||||
.object({
|
||||
breadcrumbs: z
|
||||
.object({
|
||||
title: z.string(),
|
||||
parentsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export const rawBreadcrumbsDataSchema = z.object({
|
||||
url: z.string(),
|
||||
web: z.object({
|
||||
|
||||
@@ -6,105 +6,35 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
import { router } from "../../.."
|
||||
import { PageContentTypeEnum } from "../../../enums/contentType"
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetMyPagesBreadcrumbs,
|
||||
GetMyPagesBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/AccountPage.graphql"
|
||||
import {
|
||||
GetCampaignOverviewPageBreadcrumbs,
|
||||
GetCampaignOverviewPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/CampaignOverviewPage.graphql"
|
||||
import {
|
||||
GetCampaignPageBreadcrumbs,
|
||||
GetCampaignPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/CampaignPage.graphql"
|
||||
import {
|
||||
GetCollectionPageBreadcrumbs,
|
||||
GetCollectionPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/CollectionPage.graphql"
|
||||
import {
|
||||
GetContentPageBreadcrumbs,
|
||||
GetContentPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/ContentPage.graphql"
|
||||
import {
|
||||
GetDestinationCityPageBreadcrumbs,
|
||||
GetDestinationCityPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/DestinationCityPage.graphql"
|
||||
import {
|
||||
GetDestinationCountryPageBreadcrumbs,
|
||||
GetDestinationCountryPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/DestinationCountryPage.graphql"
|
||||
import {
|
||||
GetDestinationOverviewPageBreadcrumbs,
|
||||
GetDestinationOverviewPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/DestinationOverviewPage.graphql"
|
||||
import {
|
||||
GetHotelPageBreadcrumbs,
|
||||
GetHotelPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/HotelPage.graphql"
|
||||
import {
|
||||
GetLoyaltyPageBreadcrumbs,
|
||||
GetLoyaltyPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/LoyaltyPage.graphql"
|
||||
import {
|
||||
GetPromoCampaignPageBreadcrumbs,
|
||||
GetPromoCampaignPageBreadcrumbsRefs,
|
||||
} from "../../../graphql/Query/Breadcrumbs/PromoCampaignPage.graphql"
|
||||
import { GetMyPagesBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/AccountPage.graphql"
|
||||
import { GetCampaignOverviewPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/CampaignOverviewPage.graphql"
|
||||
import { GetCampaignPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/CampaignPage.graphql"
|
||||
import { GetCollectionPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/CollectionPage.graphql"
|
||||
import { GetContentPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/ContentPage.graphql"
|
||||
import { GetDestinationCityPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/DestinationCityPage.graphql"
|
||||
import { GetDestinationCountryPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/DestinationCountryPage.graphql"
|
||||
import { GetDestinationOverviewPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/DestinationOverviewPage.graphql"
|
||||
import { GetHotelPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/HotelPage.graphql"
|
||||
import { GetLoyaltyPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/LoyaltyPage.graphql"
|
||||
import { GetPromoCampaignPageBreadcrumbs } from "../../../graphql/Query/Breadcrumbs/PromoCampaignPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
||||
import { generateRefsResponseTag } from "../../../utils/generateTag"
|
||||
import { breadcrumbsRefsSchema, breadcrumbsSchema } from "./output"
|
||||
import { getTags } from "./utils"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { breadcrumbsSchema } from "./output"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type {
|
||||
BreadcrumbsRefsSchema,
|
||||
RawBreadcrumbsSchema,
|
||||
} from "../../../types/breadcrumbs"
|
||||
import type { RawBreadcrumbsSchema } from "../../../types/breadcrumbs"
|
||||
|
||||
interface BreadcrumbsPageData<T> {
|
||||
dataKey: keyof T
|
||||
refQuery: string | DocumentNode
|
||||
query: string | DocumentNode
|
||||
}
|
||||
|
||||
const getBreadcrumbs = cache(async function fetchMemoizedBreadcrumbs<T>(
|
||||
{ dataKey, refQuery, query }: BreadcrumbsPageData<T>,
|
||||
{ dataKey, query }: BreadcrumbsPageData<T>,
|
||||
{ uid, lang }: { uid: string; lang: Lang }
|
||||
) {
|
||||
const getBreadcrumbsRefsCounter = createCounter(
|
||||
"trpc.contentstack.breadcrumbs.get.refs"
|
||||
)
|
||||
const metricsGetBreadcrumbsRefs = getBreadcrumbsRefsCounter.init({
|
||||
lang,
|
||||
uid,
|
||||
})
|
||||
|
||||
metricsGetBreadcrumbsRefs.start()
|
||||
|
||||
const refsResponse = await request<{ [K in keyof T]: BreadcrumbsRefsSchema }>(
|
||||
refQuery,
|
||||
{ locale: lang, uid },
|
||||
{
|
||||
key: generateRefsResponseTag(lang, uid, "breadcrumbs"),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
const validatedRefsData = breadcrumbsRefsSchema.safeParse(
|
||||
refsResponse.data[dataKey]
|
||||
)
|
||||
|
||||
if (!validatedRefsData.success) {
|
||||
metricsGetBreadcrumbsRefs.validationError(validatedRefsData.error)
|
||||
return []
|
||||
}
|
||||
|
||||
metricsGetBreadcrumbsRefs.success()
|
||||
|
||||
const tags = getTags(validatedRefsData.data, lang)
|
||||
|
||||
const getBreadcrumbsCounter = createCounter(
|
||||
"trpc.contentstack.breadcrumbs.get"
|
||||
)
|
||||
@@ -117,7 +47,7 @@ const getBreadcrumbs = cache(async function fetchMemoizedBreadcrumbs<T>(
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const response = await request<T>(query, variables, {
|
||||
key: tags,
|
||||
key: generateTag(lang, uid),
|
||||
ttl: "max",
|
||||
})
|
||||
|
||||
@@ -158,7 +88,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "account_page",
|
||||
refQuery: GetMyPagesBreadcrumbsRefs,
|
||||
query: GetMyPagesBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -169,7 +98,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "campaign_overview_page",
|
||||
refQuery: GetCampaignOverviewPageBreadcrumbsRefs,
|
||||
query: GetCampaignOverviewPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -180,7 +108,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "campaign_page",
|
||||
refQuery: GetCampaignPageBreadcrumbsRefs,
|
||||
query: GetCampaignPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -191,7 +118,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "collection_page",
|
||||
refQuery: GetCollectionPageBreadcrumbsRefs,
|
||||
query: GetCollectionPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -202,7 +128,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "content_page",
|
||||
refQuery: GetContentPageBreadcrumbsRefs,
|
||||
query: GetContentPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -213,7 +138,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "destination_overview_page",
|
||||
refQuery: GetDestinationOverviewPageBreadcrumbsRefs,
|
||||
query: GetDestinationOverviewPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -224,7 +148,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "destination_country_page",
|
||||
refQuery: GetDestinationCountryPageBreadcrumbsRefs,
|
||||
query: GetDestinationCountryPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -235,7 +158,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "destination_city_page",
|
||||
refQuery: GetDestinationCityPageBreadcrumbsRefs,
|
||||
query: GetDestinationCityPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -246,7 +168,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "hotel_page",
|
||||
refQuery: GetHotelPageBreadcrumbsRefs,
|
||||
query: GetHotelPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -257,7 +178,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "loyalty_page",
|
||||
refQuery: GetLoyaltyPageBreadcrumbsRefs,
|
||||
query: GetLoyaltyPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
@@ -268,7 +188,6 @@ export const breadcrumbsQueryRouter = router({
|
||||
}>(
|
||||
{
|
||||
dataKey: "promo_campaign_page",
|
||||
refQuery: GetPromoCampaignPageBreadcrumbsRefs,
|
||||
query: GetPromoCampaignPageBreadcrumbs,
|
||||
},
|
||||
variables
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import { generateTag, generateTags } from "../../../utils/generateTag"
|
||||
|
||||
import type { BreadcrumbsRefsSchema } from "../../../types/breadcrumbs"
|
||||
import type { Edges } from "../../../types/edges"
|
||||
import type { NodeRefs } from "../../../types/refs"
|
||||
|
||||
export const affix = "breadcrumbs"
|
||||
|
||||
// TODO: Make these editable in CMS?
|
||||
@@ -43,20 +37,3 @@ export const homeBreadcrumbs: {
|
||||
uid: "sv",
|
||||
},
|
||||
}
|
||||
|
||||
export function getConnections(data: BreadcrumbsRefsSchema) {
|
||||
const connections: Edges<NodeRefs>[] = []
|
||||
|
||||
if (data.web?.breadcrumbs) {
|
||||
connections.push(data.web.breadcrumbs.parentsConnection)
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
export function getTags(data: BreadcrumbsRefsSchema, lang: Lang) {
|
||||
const connections = getConnections(data)
|
||||
const tags = generateTags(lang, connections)
|
||||
tags.push(generateTag(lang, data.system.uid, affix))
|
||||
return tags
|
||||
}
|
||||
|
||||
@@ -10,19 +10,10 @@ import {
|
||||
includedHotelsSchema,
|
||||
} from "../campaignPage/output"
|
||||
import { promoHeroSchema } from "../promoCampaignPage/output"
|
||||
import {
|
||||
allCampaignsRefsSchema,
|
||||
allCampaignsSchema,
|
||||
} from "../schemas/blocks/allCampaigns"
|
||||
import {
|
||||
carouselCardsRefsSchema,
|
||||
carouselCardsSchema,
|
||||
} from "../schemas/blocks/carouselCards"
|
||||
import { allCampaignsSchema } from "../schemas/blocks/allCampaigns"
|
||||
import { carouselCardsSchema } from "../schemas/blocks/carouselCards"
|
||||
import { campaignOverviewPageHotelListingSchema } from "../schemas/blocks/hotelListing"
|
||||
import {
|
||||
linkAndTitleSchema,
|
||||
linkConnectionRefs,
|
||||
} from "../schemas/linkConnection"
|
||||
import { linkAndTitleSchema } from "../schemas/linkConnection"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
const navigationLinksSchema = z
|
||||
@@ -196,49 +187,3 @@ export const campaignOverviewPageSchema = z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
/** REFS */
|
||||
|
||||
const campaignOverviewPageHeaderRefs = z.object({
|
||||
navigation_links: z.array(linkConnectionRefs),
|
||||
})
|
||||
|
||||
const campaignOverviewPageCarouselCardsRef = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
CampaignOverviewPageEnum.ContentStack.blocks.CarouselCards
|
||||
),
|
||||
})
|
||||
.merge(carouselCardsRefsSchema)
|
||||
|
||||
const campaignOverviewPageAllCampaignsRef = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
CampaignOverviewPageEnum.ContentStack.blocks.AllCampaigns
|
||||
),
|
||||
})
|
||||
.merge(allCampaignsRefsSchema)
|
||||
|
||||
const blockRefsSchema = z.discriminatedUnion("__typename", [
|
||||
campaignOverviewPageAllCampaignsRef,
|
||||
campaignOverviewPageCarouselCardsRef,
|
||||
])
|
||||
|
||||
export const campaignOverviewPageRefsSchema = z.object({
|
||||
campaign_overview_page: z.object({
|
||||
header: campaignOverviewPageHeaderRefs,
|
||||
top_campaign_block: z.object({
|
||||
campaignConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
blocks: discriminatedUnionArray(blockRefsSchema.options).nullable(),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,72 +2,20 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetCampaignOverviewPage,
|
||||
GetCampaignOverviewPageRefs,
|
||||
} from "../../../graphql/Query/CampaignOverviewPage/CampaignOverviewPage.graphql"
|
||||
import { GetCampaignOverviewPage } from "../../../graphql/Query/CampaignOverviewPage/CampaignOverviewPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentStackUidWithServiceProcedure } from "../../../procedures"
|
||||
import { generateRefsResponseTag } from "../../../utils/generateTag"
|
||||
import {
|
||||
campaignOverviewPageRefsSchema,
|
||||
campaignOverviewPageSchema,
|
||||
} from "./output"
|
||||
import { generatePageTags } from "./utils"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { campaignOverviewPageSchema } from "./output"
|
||||
|
||||
import type {
|
||||
GetCampaignOverviewPageData,
|
||||
GetCampaignOverviewPageRefsData,
|
||||
} from "../../../types/campaignOverviewPage"
|
||||
import type { GetCampaignOverviewPageData } from "../../../types/campaignOverviewPage"
|
||||
import type { TrackingPageData } from "../../types"
|
||||
|
||||
export const campaignOverviewPageQueryRouter = router({
|
||||
get: contentStackUidWithServiceProcedure.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const getCampaignOverviewPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.campaignOverviewPage.get.refs"
|
||||
)
|
||||
const metricsGetCampaignOverviewPageRefs =
|
||||
getCampaignOverviewPageRefsCounter.init({
|
||||
lang,
|
||||
uid,
|
||||
})
|
||||
|
||||
metricsGetCampaignOverviewPageRefs.start()
|
||||
|
||||
const refVariables = { locale: lang, uid }
|
||||
const refsResponse = await request<GetCampaignOverviewPageRefsData>(
|
||||
GetCampaignOverviewPageRefs,
|
||||
refVariables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, uid),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
metricsGetCampaignOverviewPageRefs.noDataError()
|
||||
|
||||
throw notFoundError({
|
||||
message: "GetCampaignOverviewPageRefs returned no data",
|
||||
errorDetails: refVariables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedRefsData = campaignOverviewPageRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
if (!validatedRefsData.success) {
|
||||
metricsGetCampaignOverviewPageRefs.validationError(
|
||||
validatedRefsData.error
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetCampaignOverviewPageRefs.success()
|
||||
|
||||
const tags = generatePageTags(validatedRefsData.data, lang)
|
||||
const cacheKey = generateTag(lang, uid)
|
||||
|
||||
const getCampaignOverviewPageCounter = createCounter(
|
||||
"trpc.contentstack.campaignOverviewPage.get"
|
||||
@@ -84,7 +32,7 @@ export const campaignOverviewPageQueryRouter = router({
|
||||
GetCampaignOverviewPage,
|
||||
variables,
|
||||
{
|
||||
key: tags,
|
||||
key: `${cacheKey}:campaignOverviewPage`,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { CampaignOverviewPageEnum } from "../../../types/campaignOverviewPageEnum"
|
||||
import { generateTag, generateTagsFromSystem } from "../../../utils/generateTag"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type { System } from "../../../routers/contentstack/schemas/system"
|
||||
import type { CampaignOverviewPageRefs } from "../../../types/campaignOverviewPage"
|
||||
|
||||
export function generatePageTags(
|
||||
validatedData: CampaignOverviewPageRefs,
|
||||
lang: Lang
|
||||
): string[] {
|
||||
const connections = getConnections(validatedData)
|
||||
return [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, validatedData.campaign_overview_page.system.uid),
|
||||
].flat()
|
||||
}
|
||||
|
||||
export function getConnections({
|
||||
campaign_overview_page,
|
||||
}: CampaignOverviewPageRefs) {
|
||||
const connections: System["system"][] = [campaign_overview_page.system]
|
||||
|
||||
if (campaign_overview_page.header.navigation_links) {
|
||||
campaign_overview_page.header.navigation_links.forEach((link) => {
|
||||
if (link.link) {
|
||||
connections.push(link.link)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (campaign_overview_page.top_campaign_block.campaignConnection) {
|
||||
campaign_overview_page.top_campaign_block.campaignConnection.edges.forEach(
|
||||
({ node }) => {
|
||||
connections.push(node.system)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (campaign_overview_page.blocks) {
|
||||
campaign_overview_page.blocks.forEach((block) => {
|
||||
switch (block.__typename) {
|
||||
case CampaignOverviewPageEnum.ContentStack.blocks.CarouselCards: {
|
||||
block.carousel_cards.card_groups.forEach((group) => {
|
||||
group.cardConnection.edges.forEach(({ node }) => {
|
||||
connections.push(node.system)
|
||||
})
|
||||
})
|
||||
break
|
||||
}
|
||||
case CampaignOverviewPageEnum.ContentStack.blocks.AllCampaigns: {
|
||||
block.all_campaigns.campaignsConnection.edges.forEach(({ node }) => {
|
||||
if (node.system) {
|
||||
connections.push(node.system)
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
@@ -5,20 +5,11 @@ import { removeMultipleSlashes } from "@scandic-hotels/common/utils/url"
|
||||
|
||||
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 { accordionSchema } from "../schemas/blocks/accordion"
|
||||
import { carouselCardsSchema } from "../schemas/blocks/carouselCards"
|
||||
import { essentialsBlockSchema } from "../schemas/blocks/essentials"
|
||||
import { campaignPageHotelListingSchema } from "../schemas/blocks/hotelListing"
|
||||
import {
|
||||
linkConnectionRefs,
|
||||
linkConnectionSchema,
|
||||
} from "../schemas/linkConnection"
|
||||
import { linkConnectionSchema } from "../schemas/linkConnection"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
import { getCarouselCardsBlockWithBookingCodeLinks } from "./utils"
|
||||
|
||||
@@ -258,46 +249,3 @@ export const campaignPagesByHotelUidSchema = z
|
||||
}),
|
||||
})
|
||||
.transform((data) => data.all_campaign_page.items)
|
||||
|
||||
/** 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,
|
||||
}),
|
||||
})
|
||||
|
||||
export const campaignPagesByHotelUidRefsSchema = z
|
||||
.object({
|
||||
all_campaign_page: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
system: systemSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => data.all_campaign_page.items.map((item) => item.system))
|
||||
|
||||
@@ -2,64 +2,20 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetCampaignPage,
|
||||
GetCampaignPageRefs,
|
||||
} from "../../../graphql/Query/CampaignPage/CampaignPage.graphql"
|
||||
import { GetCampaignPage } from "../../../graphql/Query/CampaignPage/CampaignPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentStackUidWithServiceProcedure } from "../../../procedures"
|
||||
import { generateRefsResponseTag } from "../../../utils/generateTag"
|
||||
import { campaignPageRefsSchema, campaignPageSchema } from "./output"
|
||||
import { generatePageTags } from "./utils"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { campaignPageSchema } from "./output"
|
||||
|
||||
import type {
|
||||
GetCampaignPageData,
|
||||
GetCampaignPageRefsData,
|
||||
} from "../../../types/campaignPage"
|
||||
import type { GetCampaignPageData } from "../../../types/campaignPage"
|
||||
import type { TrackingPageData } from "../../types"
|
||||
|
||||
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 refVariables = { locale: lang, uid }
|
||||
const refsResponse = await request<GetCampaignPageRefsData>(
|
||||
GetCampaignPageRefs,
|
||||
refVariables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, uid),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
if (!refsResponse.data) {
|
||||
metricsGetCampaignPageRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetCampaignPageRefs returned no data",
|
||||
errorDetails: refVariables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedRefsData = campaignPageRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
if (!validatedRefsData.success) {
|
||||
metricsGetCampaignPageRefs.validationError(validatedRefsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetCampaignPageRefs.success()
|
||||
|
||||
const tags = generatePageTags(validatedRefsData.data, lang)
|
||||
const cacheKey = generateTag(lang, uid)
|
||||
|
||||
const getCampaignPageCounter = createCounter(
|
||||
"trpc.contentstack.campaignPage.get"
|
||||
@@ -76,7 +32,7 @@ export const campaignPageQueryRouter = router({
|
||||
GetCampaignPage,
|
||||
variables,
|
||||
{
|
||||
key: tags,
|
||||
key: `${cacheKey}:campaignPage`,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,72 +1,17 @@
|
||||
import { dt } from "@scandic-hotels/common/dt"
|
||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetCampaignPagesByHotelUid,
|
||||
GetCampaignPagesByHotelUidRefs,
|
||||
} from "../../../graphql/Query/CampaignPage/CampaignPagesByHotelUid.graphql"
|
||||
import { GetCampaignPagesByHotelUid } from "../../../graphql/Query/CampaignPage/CampaignPagesByHotelUid.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import {
|
||||
CampaignPageEnum,
|
||||
type CampaignPageRefs,
|
||||
} from "../../../types/campaignPage"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTagsFromSystem,
|
||||
} from "../../../utils/generateTag"
|
||||
import {
|
||||
campaignPagesByHotelUidRefsSchema,
|
||||
campaignPagesByHotelUidSchema,
|
||||
} from "./output"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { campaignPagesByHotelUidSchema } from "./output"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type {
|
||||
CarouselCardsBlock,
|
||||
GetCampaignPagesByHotelUidData,
|
||||
GetCampaignPagesByHotelUidRefsData,
|
||||
} from "../../../types/campaignPage"
|
||||
import type { System } from "../schemas/system"
|
||||
|
||||
export function generatePageTags(
|
||||
validatedData: CampaignPageRefs,
|
||||
lang: Lang
|
||||
): string[] {
|
||||
const connections = getConnections(validatedData)
|
||||
return [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, validatedData.campaign_page.system.uid),
|
||||
].flat()
|
||||
}
|
||||
|
||||
export function getConnections({ campaign_page }: CampaignPageRefs) {
|
||||
const connections: System["system"][] = [campaign_page.system]
|
||||
|
||||
if (campaign_page.blocks) {
|
||||
campaign_page.blocks.forEach((block) => {
|
||||
switch (block.__typename) {
|
||||
case CampaignPageEnum.ContentStack.blocks.CarouselCards: {
|
||||
block.carousel_cards.card_groups.forEach((group) => {
|
||||
group.cardConnection.edges.forEach(({ node }) => {
|
||||
connections.push(node.system)
|
||||
})
|
||||
})
|
||||
break
|
||||
}
|
||||
case CampaignPageEnum.ContentStack.blocks.Accordion: {
|
||||
if (block.accordion.length) {
|
||||
connections.push(...block.accordion.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
export function getCarouselCardsBlockWithBookingCodeLinks(
|
||||
block: CarouselCardsBlock,
|
||||
@@ -105,57 +50,6 @@ export async function getCampaignPagesByHotelPageUid(
|
||||
lang: Lang
|
||||
) {
|
||||
const today = dt().format("YYYY-MM-DD")
|
||||
const getCampaignPagesByHotelUidRefsCounter = createCounter(
|
||||
"trpc.contentstack.campaignPage.byHotelUid.get.refs"
|
||||
)
|
||||
const metricsGetCampaignPagesByHotelUidRefs =
|
||||
getCampaignPagesByHotelUidRefsCounter.init({
|
||||
lang,
|
||||
hotelPageUid,
|
||||
today,
|
||||
})
|
||||
|
||||
metricsGetCampaignPagesByHotelUidRefs.start()
|
||||
const refsTag = generateRefsResponseTag(
|
||||
lang,
|
||||
`${hotelPageUid}-${today}`,
|
||||
"hotel_page_campaigns"
|
||||
)
|
||||
const variables = {
|
||||
locale: lang,
|
||||
hotelPageUid,
|
||||
today,
|
||||
}
|
||||
const refsResponse = await request<GetCampaignPagesByHotelUidRefsData>(
|
||||
GetCampaignPagesByHotelUidRefs,
|
||||
variables,
|
||||
{
|
||||
key: refsTag,
|
||||
ttl: "1d",
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
metricsGetCampaignPagesByHotelUidRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetCampaignPagesByHotelUidRefs returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedRefsData = campaignPagesByHotelUidRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
if (!validatedRefsData.success) {
|
||||
metricsGetCampaignPagesByHotelUidRefs.validationError(
|
||||
validatedRefsData.error
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetCampaignPagesByHotelUidRefs.success()
|
||||
|
||||
const tags = generateTagsFromSystem(lang, validatedRefsData.data)
|
||||
|
||||
const getCampaignPagesByHotelUidCounter = createCounter(
|
||||
"trpc.contentstack.campaignPage.byHotelUid.get"
|
||||
@@ -169,15 +63,17 @@ export async function getCampaignPagesByHotelPageUid(
|
||||
|
||||
metricsGetCampaignPagesByHotelUid.start()
|
||||
|
||||
const variables = {
|
||||
locale: lang,
|
||||
hotelPageUid,
|
||||
today,
|
||||
}
|
||||
|
||||
const response = await request<GetCampaignPagesByHotelUidData>(
|
||||
GetCampaignPagesByHotelUid,
|
||||
variables,
|
||||
{
|
||||
locale: lang,
|
||||
hotelPageUid,
|
||||
today,
|
||||
},
|
||||
{
|
||||
key: [...tags, refsTag],
|
||||
key: generateTag(lang, `${hotelPageUid}-${today}`),
|
||||
ttl: "1d",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,30 +4,15 @@ import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/i
|
||||
|
||||
import { CollectionPageEnum } from "../../../types/collectionPage"
|
||||
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
cardGridRefsSchema,
|
||||
cardsGridSchema,
|
||||
} from "../schemas/blocks/cardsGrid"
|
||||
import {
|
||||
dynamicContentRefsSchema,
|
||||
dynamicContentSchema as blockDynamicContentSchema,
|
||||
} from "../schemas/blocks/dynamicContent"
|
||||
import {
|
||||
shortcutsRefsSchema,
|
||||
shortcutsSchema,
|
||||
} from "../schemas/blocks/shortcuts"
|
||||
import { uspGridRefsSchema, uspGridSchema } from "../schemas/blocks/uspGrid"
|
||||
import {
|
||||
videoCardRefsSchema,
|
||||
videoCardSchema,
|
||||
} from "../schemas/blocks/videoCard"
|
||||
import {
|
||||
linkAndTitleSchema,
|
||||
linkConnectionRefs,
|
||||
} from "../schemas/linkConnection"
|
||||
import { cardsGridSchema } from "../schemas/blocks/cardsGrid"
|
||||
import { dynamicContentSchema as blockDynamicContentSchema } from "../schemas/blocks/dynamicContent"
|
||||
import { shortcutsSchema } from "../schemas/blocks/shortcuts"
|
||||
import { uspGridSchema } from "../schemas/blocks/uspGrid"
|
||||
import { videoCardSchema } from "../schemas/blocks/videoCard"
|
||||
import { linkAndTitleSchema } from "../schemas/linkConnection"
|
||||
import { internalOrExternalLinkSchema } from "../schemas/pageLinks"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
import { transformedVideoSchema, videoRefSchema } from "../schemas/video"
|
||||
import { transformedVideoSchema } from "../schemas/video"
|
||||
|
||||
// Block schemas
|
||||
export const collectionPageCards = z
|
||||
@@ -116,60 +101,3 @@ export const collectionPageSchema = z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
/** REFS */
|
||||
const collectionPageCardsRefs = z
|
||||
.object({
|
||||
__typename: z.literal(CollectionPageEnum.ContentStack.blocks.CardsGrid),
|
||||
})
|
||||
.merge(cardGridRefsSchema)
|
||||
|
||||
const collectionPageShortcutsRefs = z
|
||||
.object({
|
||||
__typename: z.literal(CollectionPageEnum.ContentStack.blocks.Shortcuts),
|
||||
})
|
||||
.merge(shortcutsRefsSchema)
|
||||
|
||||
const collectionPageUspGridRefs = z
|
||||
.object({
|
||||
__typename: z.literal(CollectionPageEnum.ContentStack.blocks.UspGrid),
|
||||
})
|
||||
.merge(uspGridRefsSchema)
|
||||
|
||||
const collectionPageDynamicContentRefs = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
CollectionPageEnum.ContentStack.blocks.DynamicContent
|
||||
),
|
||||
})
|
||||
.merge(dynamicContentRefsSchema)
|
||||
|
||||
const collectionPageVideoCardRefs = z
|
||||
.object({
|
||||
__typename: z.literal(CollectionPageEnum.ContentStack.blocks.VideoCard),
|
||||
})
|
||||
.merge(videoCardRefsSchema)
|
||||
|
||||
const collectionPageBlockRefsItem = z.discriminatedUnion("__typename", [
|
||||
collectionPageShortcutsRefs,
|
||||
collectionPageDynamicContentRefs,
|
||||
collectionPageCardsRefs,
|
||||
collectionPageUspGridRefs,
|
||||
collectionPageVideoCardRefs,
|
||||
])
|
||||
|
||||
const collectionPageHeaderRefs = z.object({
|
||||
navigation_links: z.array(linkConnectionRefs),
|
||||
top_primary_button: linkConnectionRefs.nullable(),
|
||||
})
|
||||
|
||||
export const collectionPageRefsSchema = z.object({
|
||||
collection_page: z.object({
|
||||
hero_video: videoRefSchema.nullish(),
|
||||
header: collectionPageHeaderRefs,
|
||||
blocks: discriminatedUnionArray(
|
||||
collectionPageBlockRefsItem.options
|
||||
).nullable(),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -4,12 +4,8 @@ import { router } from "../../.."
|
||||
import { GetCollectionPage } from "../../../graphql/Query/CollectionPage/CollectionPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { collectionPageSchema } from "./output"
|
||||
import {
|
||||
fetchCollectionPageRefs,
|
||||
generatePageTags,
|
||||
validateCollectionPageRefs,
|
||||
} from "./utils"
|
||||
|
||||
import type { GetCollectionPageSchema } from "../../../types/collectionPage"
|
||||
import type { TrackingPageData } from "../../types"
|
||||
@@ -18,17 +14,7 @@ export const collectionPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const collectionPageRefsData = await fetchCollectionPageRefs(lang, uid)
|
||||
|
||||
const collectionPageRefs = validateCollectionPageRefs(
|
||||
collectionPageRefsData,
|
||||
lang,
|
||||
uid
|
||||
)
|
||||
if (!collectionPageRefs) {
|
||||
return null
|
||||
}
|
||||
const tags = generatePageTags(collectionPageRefs, lang)
|
||||
const cacheKey = generateTag(lang, uid)
|
||||
|
||||
const getCollectionPageCounter = createCounter(
|
||||
"trpc.contentstack.collectionPage.get"
|
||||
@@ -44,7 +30,7 @@ export const collectionPageQueryRouter = router({
|
||||
GetCollectionPage,
|
||||
{ locale: lang, uid },
|
||||
{
|
||||
key: tags,
|
||||
key: `${cacheKey}:collectionPage`,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { notFoundError } from "../../../errors"
|
||||
import { GetCollectionPageRefs } from "../../../graphql/Query/CollectionPage/CollectionPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import {
|
||||
CollectionPageEnum,
|
||||
type CollectionPageRefs,
|
||||
type GetCollectionPageRefsSchema,
|
||||
} from "../../../types/collectionPage"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTagsFromAssetSystem,
|
||||
generateTagsFromSystem,
|
||||
} from "../../../utils/generateTag"
|
||||
import { collectionPageRefsSchema } from "./output"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type { AssetSystem, System } from "../schemas/system"
|
||||
|
||||
export async function fetchCollectionPageRefs(lang: Lang, uid: string) {
|
||||
const getCollectionPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.collectionPage.get.refs"
|
||||
)
|
||||
const metricsGetCollectionPageRefs = getCollectionPageRefsCounter.init({
|
||||
lang,
|
||||
uid,
|
||||
})
|
||||
|
||||
metricsGetCollectionPageRefs.start()
|
||||
|
||||
const cacheKey = generateRefsResponseTag(lang, uid)
|
||||
const variables = {
|
||||
locale: lang,
|
||||
uid,
|
||||
}
|
||||
const refsResponse = await request<GetCollectionPageRefsSchema>(
|
||||
GetCollectionPageRefs,
|
||||
variables,
|
||||
{
|
||||
key: cacheKey,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
metricsGetCollectionPageRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetCollectionPageRefs returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
return refsResponse.data
|
||||
}
|
||||
|
||||
export function validateCollectionPageRefs(
|
||||
data: GetCollectionPageRefsSchema,
|
||||
lang: Lang,
|
||||
uid: string
|
||||
) {
|
||||
const getCollectionPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.collectionPage.get.refs"
|
||||
)
|
||||
const metricsGetCollectionPageRefs = getCollectionPageRefsCounter.init({
|
||||
lang,
|
||||
uid,
|
||||
})
|
||||
|
||||
const validatedData = collectionPageRefsSchema.safeParse(data)
|
||||
if (!validatedData.success) {
|
||||
metricsGetCollectionPageRefs.validationError(validatedData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetCollectionPageRefs.success()
|
||||
|
||||
return validatedData.data
|
||||
}
|
||||
|
||||
export function generatePageTags(
|
||||
validatedData: CollectionPageRefs,
|
||||
lang: Lang
|
||||
): string[] {
|
||||
const { connections, assetConnections } = getConnections(validatedData)
|
||||
return [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTagsFromAssetSystem(assetConnections),
|
||||
generateTag(lang, validatedData.collection_page.system.uid),
|
||||
].flat()
|
||||
}
|
||||
|
||||
export function getConnections({ collection_page }: CollectionPageRefs) {
|
||||
const connections: System["system"][] = [collection_page.system]
|
||||
const assetConnections: AssetSystem[] = []
|
||||
|
||||
if (collection_page.hero_video?.sourceConnection.edges[0]) {
|
||||
assetConnections.push(
|
||||
collection_page.hero_video.sourceConnection.edges[0].node
|
||||
)
|
||||
}
|
||||
|
||||
if (collection_page.blocks) {
|
||||
collection_page.blocks.forEach((block) => {
|
||||
const typeName = block.__typename
|
||||
switch (typeName) {
|
||||
case CollectionPageEnum.ContentStack.blocks.Shortcuts:
|
||||
if (block.shortcuts.shortcuts.length) {
|
||||
connections.push(...block.shortcuts.shortcuts.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
case CollectionPageEnum.ContentStack.blocks.CardsGrid:
|
||||
if (block.cards_grid.length) {
|
||||
connections.push(...block.cards_grid)
|
||||
}
|
||||
break
|
||||
case CollectionPageEnum.ContentStack.blocks.UspGrid:
|
||||
if (block.usp_grid.length) {
|
||||
connections.push(...block.usp_grid.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
case CollectionPageEnum.ContentStack.blocks.VideoCard:
|
||||
if (block.video_card?.system) {
|
||||
connections.push(block.video_card.system)
|
||||
}
|
||||
if (block.video_card?.video.sourceConnection.edges[0]) {
|
||||
assetConnections.push(
|
||||
block.video_card.video.sourceConnection.edges[0].node
|
||||
)
|
||||
}
|
||||
break
|
||||
case CollectionPageEnum.ContentStack.blocks.DynamicContent:
|
||||
break
|
||||
default:
|
||||
const _exhaustiveCheck: never = typeName
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return { connections, assetConnections }
|
||||
}
|
||||
@@ -4,68 +4,29 @@ import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/i
|
||||
|
||||
import { ContentPageEnum } from "../../../types/contentPage"
|
||||
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
accordionRefsSchema,
|
||||
accordionSchema,
|
||||
} from "../schemas/blocks/accordion"
|
||||
import {
|
||||
cardGridRefsSchema,
|
||||
cardsGridSchema,
|
||||
} from "../schemas/blocks/cardsGrid"
|
||||
import {
|
||||
contentRefsSchema as blockContentRefsSchema,
|
||||
contentSchema as blockContentSchema,
|
||||
} from "../schemas/blocks/content"
|
||||
import {
|
||||
dynamicContentRefsSchema,
|
||||
dynamicContentSchema as blockDynamicContentSchema,
|
||||
} from "../schemas/blocks/dynamicContent"
|
||||
import { accordionSchema } from "../schemas/blocks/accordion"
|
||||
import { cardsGridSchema } from "../schemas/blocks/cardsGrid"
|
||||
import { contentSchema as blockContentSchema } from "../schemas/blocks/content"
|
||||
import { dynamicContentSchema as blockDynamicContentSchema } from "../schemas/blocks/dynamicContent"
|
||||
import { contentPageHotelListingSchema } from "../schemas/blocks/hotelListing"
|
||||
import { jotformRefsSchema, jotformSchema } from "../schemas/blocks/jotform"
|
||||
import {
|
||||
shortcutsRefsSchema,
|
||||
shortcutsSchema,
|
||||
} from "../schemas/blocks/shortcuts"
|
||||
import { jotformSchema } from "../schemas/blocks/jotform"
|
||||
import { shortcutsSchema } from "../schemas/blocks/shortcuts"
|
||||
import { tableSchema } from "../schemas/blocks/table"
|
||||
import { textColsRefsSchema, textColsSchema } from "../schemas/blocks/textCols"
|
||||
import { uspGridRefsSchema, uspGridSchema } from "../schemas/blocks/uspGrid"
|
||||
import { videoBlockRefsSchema, videoBlockSchema } from "../schemas/blocks/video"
|
||||
import {
|
||||
videoCardRefsSchema,
|
||||
videoCardSchema,
|
||||
} from "../schemas/blocks/videoCard"
|
||||
import {
|
||||
dynamicContentRefsSchema as headerDynamicContentRefsSchema,
|
||||
dynamicContentSchema as headerDynamicContentSchema,
|
||||
} from "../schemas/headers/dynamicContent"
|
||||
import {
|
||||
linkAndTitleSchema,
|
||||
linkConnectionRefs,
|
||||
} from "../schemas/linkConnection"
|
||||
import { textColsSchema } from "../schemas/blocks/textCols"
|
||||
import { uspGridSchema } from "../schemas/blocks/uspGrid"
|
||||
import { videoBlockSchema } from "../schemas/blocks/video"
|
||||
import { videoCardSchema } from "../schemas/blocks/videoCard"
|
||||
import { dynamicContentSchema as headerDynamicContentSchema } from "../schemas/headers/dynamicContent"
|
||||
import { linkAndTitleSchema } from "../schemas/linkConnection"
|
||||
import { internalOrExternalLinkSchema } from "../schemas/pageLinks"
|
||||
import {
|
||||
contentRefsSchema as sidebarContentRefsSchema,
|
||||
contentSchema as sidebarContentSchema,
|
||||
} from "../schemas/sidebar/content"
|
||||
import { contentSchema as sidebarContentSchema } from "../schemas/sidebar/content"
|
||||
import { dynamicContentSchema as sidebarDynamicContentSchema } from "../schemas/sidebar/dynamicContent"
|
||||
import {
|
||||
joinLoyaltyContactRefsSchema,
|
||||
joinLoyaltyContactSchema,
|
||||
} from "../schemas/sidebar/joinLoyaltyContact"
|
||||
import {
|
||||
quickLinksRefschema,
|
||||
quickLinksSchema,
|
||||
} from "../schemas/sidebar/quickLinks"
|
||||
import {
|
||||
scriptedCardRefschema,
|
||||
scriptedCardsSchema,
|
||||
} from "../schemas/sidebar/scriptedCard"
|
||||
import {
|
||||
teaserCardRefschema,
|
||||
teaserCardsSchema,
|
||||
} from "../schemas/sidebar/teaserCard"
|
||||
import { joinLoyaltyContactSchema } from "../schemas/sidebar/joinLoyaltyContact"
|
||||
import { quickLinksSchema } from "../schemas/sidebar/quickLinks"
|
||||
import { scriptedCardsSchema } from "../schemas/sidebar/scriptedCard"
|
||||
import { teaserCardsSchema } from "../schemas/sidebar/teaserCard"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
import { transformedVideoSchema, videoRefSchema } from "../schemas/video"
|
||||
import { transformedVideoSchema } from "../schemas/video"
|
||||
|
||||
// Block schemas
|
||||
export const contentPageCards = z
|
||||
@@ -250,137 +211,3 @@ export const contentPageSchema = z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
/** REFS */
|
||||
const contentPageCardsRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.CardsGrid),
|
||||
})
|
||||
.merge(cardGridRefsSchema)
|
||||
|
||||
const contentPageBlockContentRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Content),
|
||||
})
|
||||
.merge(blockContentRefsSchema)
|
||||
|
||||
const contentPageDynamicContentRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.DynamicContent),
|
||||
})
|
||||
.merge(dynamicContentRefsSchema)
|
||||
|
||||
const contentPageShortcutsRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Shortcuts),
|
||||
})
|
||||
.merge(shortcutsRefsSchema)
|
||||
|
||||
const contentPageTextColsRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.TextCols),
|
||||
})
|
||||
.merge(textColsRefsSchema)
|
||||
|
||||
const contentPageUspGridRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.UspGrid),
|
||||
})
|
||||
.merge(uspGridRefsSchema)
|
||||
|
||||
const contentPageAccordionRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Accordion),
|
||||
})
|
||||
.merge(accordionRefsSchema)
|
||||
|
||||
const contentPageVideoCardRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.VideoCard),
|
||||
})
|
||||
.merge(videoCardRefsSchema)
|
||||
|
||||
const contentPageVideoRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Video),
|
||||
})
|
||||
.merge(videoBlockRefsSchema)
|
||||
|
||||
const contentPageJotformRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Jotform),
|
||||
})
|
||||
.merge(jotformRefsSchema)
|
||||
|
||||
const contentPageBlockRefsItem = z.discriminatedUnion("__typename", [
|
||||
contentPageAccordionRefs,
|
||||
contentPageBlockContentRefs,
|
||||
contentPageShortcutsRefs,
|
||||
contentPageCardsRefs,
|
||||
contentPageDynamicContentRefs,
|
||||
contentPageTextColsRefs,
|
||||
contentPageUspGridRefs,
|
||||
contentPageVideoCardRefs,
|
||||
contentPageJotformRefs,
|
||||
contentPageVideoRefs,
|
||||
])
|
||||
|
||||
const contentPageSidebarContentRef = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.sidebar.Content),
|
||||
})
|
||||
.merge(sidebarContentRefsSchema)
|
||||
|
||||
const contentPageSidebarJoinLoyaltyContactRef = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
ContentPageEnum.ContentStack.sidebar.JoinLoyaltyContact
|
||||
),
|
||||
})
|
||||
.merge(joinLoyaltyContactRefsSchema)
|
||||
|
||||
const contentPageSidebarScriptedCardRef = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.sidebar.ScriptedCard),
|
||||
})
|
||||
.merge(scriptedCardRefschema)
|
||||
|
||||
const contentPageSidebarTeaserCardRef = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.sidebar.TeaserCard),
|
||||
})
|
||||
.merge(teaserCardRefschema)
|
||||
|
||||
const contentPageSidebarQuickLinksRef = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.sidebar.QuickLinks),
|
||||
})
|
||||
.merge(quickLinksRefschema)
|
||||
|
||||
const contentPageSidebarRefsItem = z.discriminatedUnion("__typename", [
|
||||
contentPageSidebarContentRef,
|
||||
contentPageSidebarJoinLoyaltyContactRef,
|
||||
contentPageSidebarScriptedCardRef,
|
||||
contentPageSidebarTeaserCardRef,
|
||||
contentPageSidebarQuickLinksRef,
|
||||
])
|
||||
|
||||
const contentPageHeaderRefs = z.object({
|
||||
navigation_links: z.array(linkConnectionRefs),
|
||||
top_primary_button: linkConnectionRefs.nullable(),
|
||||
dynamic_content: headerDynamicContentRefsSchema.nullish(),
|
||||
})
|
||||
|
||||
export const contentPageRefsSchema = z.object({
|
||||
content_page: z.object({
|
||||
hero_video: videoRefSchema.nullish(),
|
||||
header: contentPageHeaderRefs,
|
||||
blocks: discriminatedUnionArray(
|
||||
contentPageBlockRefsItem.options
|
||||
).nullable(),
|
||||
sidebar: discriminatedUnionArray(
|
||||
contentPageSidebarRefsItem.options
|
||||
).nullable(),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -8,8 +8,8 @@ import {
|
||||
GetContentPageBlocksBatch2,
|
||||
} from "../../../graphql/Query/ContentPage/ContentPage.graphql"
|
||||
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { contentPageSchema } from "./output"
|
||||
import { fetchContentPageRefs, generatePageTags } from "./utils"
|
||||
|
||||
import type { GetContentPageSchema } from "../../../types/contentPage"
|
||||
import type { TrackingPageData } from "../../types"
|
||||
@@ -18,13 +18,8 @@ export const contentPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const contentPageRefs = await fetchContentPageRefs(lang, uid)
|
||||
|
||||
if (!contentPageRefs) {
|
||||
return null
|
||||
}
|
||||
|
||||
const tags = generatePageTags(contentPageRefs, lang)
|
||||
// by fetching references when a child entry is published
|
||||
const cacheKey = generateTag(lang, uid)
|
||||
|
||||
const getContentPageCounter = createCounter(
|
||||
"trpc.contentstack.contentPage.get"
|
||||
@@ -41,7 +36,7 @@ export const contentPageQueryRouter = router({
|
||||
document: GetContentPage,
|
||||
variables: { locale: lang, uid },
|
||||
cacheOptions: {
|
||||
key: `${tags.join(",")}:contentPage`,
|
||||
key: `${cacheKey}:contentPage`,
|
||||
ttl: "max",
|
||||
},
|
||||
},
|
||||
@@ -50,7 +45,7 @@ export const contentPageQueryRouter = router({
|
||||
document: GetContentPageBlocksBatch1,
|
||||
variables: { locale: lang, uid },
|
||||
cacheOptions: {
|
||||
key: `${tags.join(",")}:contentPageBlocksBatch1`,
|
||||
key: `${cacheKey}:contentPageBlocksBatch1`,
|
||||
ttl: "max",
|
||||
},
|
||||
},
|
||||
@@ -59,7 +54,7 @@ export const contentPageQueryRouter = router({
|
||||
document: GetContentPageBlocksBatch2,
|
||||
variables: { locale: lang, uid },
|
||||
cacheOptions: {
|
||||
key: `${tags.join(",")}:contentPageBlocksBatch2`,
|
||||
key: `${cacheKey}:contentPageBlocksBatch2`,
|
||||
ttl: "max",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { notFoundError } from "../../../errors"
|
||||
import { batchRequest } from "../../../graphql/batchRequest"
|
||||
import {
|
||||
GetContentPageBlocksRefs,
|
||||
GetContentPageRefs,
|
||||
} from "../../../graphql/Query/ContentPage/ContentPage.graphql"
|
||||
import { ContentPageEnum } from "../../../types/contentPage"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTagsFromAssetSystem,
|
||||
generateTagsFromSystem,
|
||||
} from "../../../utils/generateTag"
|
||||
import { contentPageRefsSchema } from "./output"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type {
|
||||
ContentPageRefs,
|
||||
GetContentPageRefsSchema,
|
||||
} from "../../../types/contentPage"
|
||||
import type { AssetSystem, System } from "../schemas/system"
|
||||
|
||||
export async function fetchContentPageRefs(lang: Lang, uid: string) {
|
||||
const getContentPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.contentPage.get.refs"
|
||||
)
|
||||
const metricsGetContentPageRefs = getContentPageRefsCounter.init({
|
||||
lang,
|
||||
uid,
|
||||
})
|
||||
|
||||
metricsGetContentPageRefs.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const res = await batchRequest<GetContentPageRefsSchema>([
|
||||
{
|
||||
document: GetContentPageRefs,
|
||||
variables,
|
||||
cacheOptions: {
|
||||
key: generateRefsResponseTag(lang, uid),
|
||||
ttl: "max",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: GetContentPageBlocksRefs,
|
||||
variables,
|
||||
cacheOptions: {
|
||||
key: generateTag(lang, uid + 1),
|
||||
ttl: "max",
|
||||
},
|
||||
},
|
||||
])
|
||||
if (!res.data) {
|
||||
metricsGetContentPageRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetContentPageRefs/GetContentPageBlocksRefs returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedData = contentPageRefsSchema.safeParse(res.data)
|
||||
if (!validatedData.success) {
|
||||
metricsGetContentPageRefs.validationError(validatedData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetContentPageRefs.success()
|
||||
|
||||
return validatedData.data
|
||||
}
|
||||
|
||||
export function generatePageTags(
|
||||
validatedData: ContentPageRefs,
|
||||
lang: Lang
|
||||
): string[] {
|
||||
const { connections, assetConnections } = getConnections(validatedData)
|
||||
return [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTagsFromAssetSystem(assetConnections),
|
||||
generateTag(lang, validatedData.content_page.system.uid),
|
||||
].flat()
|
||||
}
|
||||
|
||||
export function getConnections({ content_page }: ContentPageRefs) {
|
||||
const connections: System["system"][] = [content_page.system]
|
||||
const assetConnections: AssetSystem[] = []
|
||||
|
||||
if (content_page.hero_video?.sourceConnection.edges[0]) {
|
||||
assetConnections.push(
|
||||
content_page.hero_video.sourceConnection.edges[0].node
|
||||
)
|
||||
}
|
||||
|
||||
if (content_page.blocks) {
|
||||
content_page.blocks.forEach((block) => {
|
||||
const typeName = block.__typename
|
||||
switch (typeName) {
|
||||
case ContentPageEnum.ContentStack.blocks.Accordion:
|
||||
if (block.accordion.length) {
|
||||
connections.push(...block.accordion.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.Content:
|
||||
if (block?.content?.length) {
|
||||
block.content.forEach((contentBlock) => {
|
||||
if ("system" in contentBlock) {
|
||||
assetConnections.push(contentBlock)
|
||||
} else {
|
||||
connections.push(contentBlock)
|
||||
}
|
||||
})
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.CardsGrid:
|
||||
if (block.cards_grid.length) {
|
||||
connections.push(...block.cards_grid)
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.DynamicContent:
|
||||
if (block.dynamic_content.link) {
|
||||
connections.push(block.dynamic_content.link)
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.Shortcuts:
|
||||
if (block.shortcuts.shortcuts.length) {
|
||||
connections.push(...block.shortcuts.shortcuts.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.TextCols:
|
||||
if (block.text_cols.length) {
|
||||
connections.push(...block.text_cols)
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.UspGrid:
|
||||
if (block.usp_grid.length) {
|
||||
connections.push(...block.usp_grid.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.CardsGrid:
|
||||
if (block.cards_grid.length) {
|
||||
block.cards_grid.forEach((card) => {
|
||||
connections.push(card)
|
||||
})
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.VideoCard:
|
||||
if (block.video_card) {
|
||||
connections.push(block.video_card.system)
|
||||
}
|
||||
if (block.video_card?.video.sourceConnection.edges[0]) {
|
||||
assetConnections.push(
|
||||
block.video_card.video.sourceConnection.edges[0].node
|
||||
)
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.Video:
|
||||
if (block.video?.sourceConnection.edges[0]) {
|
||||
assetConnections.push(block.video.sourceConnection.edges[0].node)
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.Jotform:
|
||||
if (block.jotform) {
|
||||
connections.push(block.jotform.system)
|
||||
}
|
||||
break
|
||||
default:
|
||||
const _exhaustiveCheck: never = typeName
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (content_page.sidebar) {
|
||||
content_page.sidebar.forEach((block) => {
|
||||
const typeName = block.__typename
|
||||
switch (typeName) {
|
||||
case ContentPageEnum.ContentStack.sidebar.Content:
|
||||
if (block.content?.length) {
|
||||
block.content.forEach((contentBlock) => {
|
||||
if ("system" in contentBlock) {
|
||||
assetConnections.push(contentBlock)
|
||||
} else {
|
||||
connections.push(contentBlock)
|
||||
}
|
||||
})
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.sidebar.JoinLoyaltyContact:
|
||||
if (block.join_loyalty_contact?.button) {
|
||||
connections.push(block.join_loyalty_contact.button)
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.sidebar.ScriptedCard:
|
||||
if (block.scripted_card?.length) {
|
||||
connections.push(...block.scripted_card)
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.sidebar.TeaserCard:
|
||||
if (block.teaser_card?.length) {
|
||||
connections.push(...block.teaser_card)
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.sidebar.QuickLinks:
|
||||
if (block.shortcuts.shortcuts.length) {
|
||||
connections.push(...block.shortcuts.shortcuts.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
default:
|
||||
const _exhaustiveCheck: never = typeName
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
return { connections, assetConnections }
|
||||
}
|
||||
@@ -6,21 +6,11 @@ import { removeMultipleSlashes } from "@scandic-hotels/common/utils/url"
|
||||
import { DestinationCityPageEnum } from "../../../types/destinationCityPage"
|
||||
import { isDefined } from "../../../utils"
|
||||
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
accordionRefsSchema,
|
||||
accordionSchema,
|
||||
} from "../schemas/blocks/accordion"
|
||||
import { contentRefsSchema, contentSchema } from "../schemas/blocks/content"
|
||||
import {
|
||||
destinationFiltersRefsSchema,
|
||||
transformedDestinationFiltersSchema,
|
||||
} from "../schemas/destinationFilters"
|
||||
import { accordionSchema } from "../schemas/blocks/accordion"
|
||||
import { contentSchema } from "../schemas/blocks/content"
|
||||
import { transformedDestinationFiltersSchema } from "../schemas/destinationFilters"
|
||||
import { mapLocationSchema } from "../schemas/mapLocation"
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../schemas/pageLinks"
|
||||
import { linkUnionSchema, transformPageLink } from "../schemas/pageLinks"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
import type { ImageVaultAsset } from "@scandic-hotels/common/utils/imageVault"
|
||||
@@ -227,47 +217,3 @@ export const batchedCityPageUrlsSchema = z
|
||||
.transform((allItems) => {
|
||||
return allItems.flatMap((item) => item.data)
|
||||
})
|
||||
|
||||
/** REFS */
|
||||
const destinationCityPageContentRefs = z
|
||||
.object({
|
||||
__typename: z.literal(DestinationCityPageEnum.ContentStack.blocks.Content),
|
||||
})
|
||||
.merge(contentRefsSchema)
|
||||
|
||||
const destinationCityPageAccordionRefs = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
DestinationCityPageEnum.ContentStack.blocks.Accordion
|
||||
),
|
||||
})
|
||||
.merge(accordionRefsSchema)
|
||||
|
||||
const blocksRefsSchema = z.discriminatedUnion("__typename", [
|
||||
destinationCityPageAccordionRefs,
|
||||
destinationCityPageContentRefs,
|
||||
])
|
||||
|
||||
export const destinationCityPageRefsSchema = z.object({
|
||||
destination_city_page: z.object({
|
||||
destination_settings: destinationCityPageDestinationSettingsSchema,
|
||||
sidepeek_content: z
|
||||
.object({
|
||||
content: z
|
||||
.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.nullish(),
|
||||
})
|
||||
.nullish(),
|
||||
blocks: discriminatedUnionArray(blocksRefsSchema.options).nullable(),
|
||||
seo_filters: destinationFiltersRefsSchema,
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,67 +2,21 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetDestinationCityPage,
|
||||
GetDestinationCityPageRefs,
|
||||
} from "../../../graphql/Query/DestinationCityPage/DestinationCityPage.graphql"
|
||||
import { GetDestinationCityPage } from "../../../graphql/Query/DestinationCityPage/DestinationCityPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentStackUidWithServiceProcedure } from "../../../procedures"
|
||||
import { generateRefsResponseTag } from "../../../utils/generateTag"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { getCityByCityIdentifier } from "../../hotels/services/getCityByCityIdentifier"
|
||||
import {
|
||||
destinationCityPageRefsSchema,
|
||||
destinationCityPageSchema,
|
||||
} from "./output"
|
||||
import { generatePageTags } from "./utils"
|
||||
import { destinationCityPageSchema } from "./output"
|
||||
|
||||
import type {
|
||||
GetDestinationCityPageData,
|
||||
GetDestinationCityPageRefsSchema,
|
||||
} from "../../../types/destinationCityPage"
|
||||
import type { GetDestinationCityPageData } from "../../../types/destinationCityPage"
|
||||
import type { TrackingPageData } from "../../types"
|
||||
|
||||
export const destinationCityPageQueryRouter = router({
|
||||
get: contentStackUidWithServiceProcedure.query(async ({ ctx }) => {
|
||||
const { lang, uid, serviceToken } = ctx
|
||||
|
||||
const getDestinationCityPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.destinationCityPage.get.refs"
|
||||
)
|
||||
const metricsGetDestinationCityPageRefs =
|
||||
getDestinationCityPageRefsCounter.init({ lang, uid })
|
||||
|
||||
metricsGetDestinationCityPageRefs.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const refsResponse = await request<GetDestinationCityPageRefsSchema>(
|
||||
GetDestinationCityPageRefs,
|
||||
variables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, uid),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
metricsGetDestinationCityPageRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetDestinationCityPageRefs returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedRefsData = destinationCityPageRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
if (!validatedRefsData.success) {
|
||||
metricsGetDestinationCityPageRefs.validationError(validatedRefsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetDestinationCityPageRefs.success()
|
||||
|
||||
const tags = generatePageTags(validatedRefsData.data, lang)
|
||||
const cacheKey = generateTag(lang, uid)
|
||||
|
||||
const getDestinationCityPageCounter = createCounter(
|
||||
"trpc.contentstack.destinationCityPage.get"
|
||||
@@ -74,11 +28,12 @@ export const destinationCityPageQueryRouter = router({
|
||||
|
||||
metricsGetDestinationCityPage.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const response = await request<GetDestinationCityPageData>(
|
||||
GetDestinationCityPage,
|
||||
variables,
|
||||
{
|
||||
key: tags,
|
||||
key: `${cacheKey}:destinationCityPage`,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -3,72 +3,14 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
import { GetCityPageCount } from "../../../graphql/Query/DestinationCityPage/DestinationCityPageCount.graphql"
|
||||
import { GetCityPageUrls } from "../../../graphql/Query/DestinationCityPage/DestinationCityPageUrl.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { DestinationCityPageEnum } from "../../../types/destinationCityPage"
|
||||
import { generateTag, generateTagsFromSystem } from "../../../utils/generateTag"
|
||||
import { batchedCityPageUrlsSchema, cityPageCountSchema } from "./output"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type {
|
||||
DestinationCityPageRefs,
|
||||
GetCityPageCountData,
|
||||
GetCityPageUrlsData,
|
||||
} from "../../../types/destinationCityPage"
|
||||
import type { System } from "../schemas/system"
|
||||
|
||||
export function generatePageTags(
|
||||
validatedData: DestinationCityPageRefs,
|
||||
lang: Lang
|
||||
): string[] {
|
||||
const connections = getConnections(validatedData)
|
||||
return [
|
||||
// This tag is added for the city list data on country pages to invalidate the list when city page changes.
|
||||
generateTag(
|
||||
lang,
|
||||
`city_list_data:${validatedData.destination_city_page.destination_settings.city}`
|
||||
),
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, validatedData.destination_city_page.system.uid),
|
||||
].flat()
|
||||
}
|
||||
|
||||
export function getConnections({
|
||||
destination_city_page,
|
||||
}: DestinationCityPageRefs) {
|
||||
const connections: System["system"][] = [destination_city_page.system]
|
||||
if (destination_city_page.blocks) {
|
||||
destination_city_page.blocks.forEach((block) => {
|
||||
switch (block.__typename) {
|
||||
case DestinationCityPageEnum.ContentStack.blocks.Accordion: {
|
||||
if (block.accordion.length) {
|
||||
connections.push(...block.accordion.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
}
|
||||
case DestinationCityPageEnum.ContentStack.blocks.Content:
|
||||
{
|
||||
if (block?.content?.length) {
|
||||
// TS has trouble infering the filtered types
|
||||
// @ts-ignore
|
||||
connections.push(...block.content)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
if (destination_city_page.sidepeek_content) {
|
||||
destination_city_page.sidepeek_content?.content?.embedded_itemsConnection.edges.forEach(
|
||||
({ node }) => {
|
||||
if (node.system) {
|
||||
connections.push(node.system)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
export async function getCityPageCount(lang: Lang) {
|
||||
const getCityPageCountCounter = createCounter(
|
||||
|
||||
@@ -6,21 +6,11 @@ import { removeMultipleSlashes } from "@scandic-hotels/common/utils/url"
|
||||
|
||||
import { DestinationCountryPageEnum } from "../../../types/destinationCountryPage"
|
||||
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
accordionRefsSchema,
|
||||
accordionSchema,
|
||||
} from "../schemas/blocks/accordion"
|
||||
import { contentRefsSchema, contentSchema } from "../schemas/blocks/content"
|
||||
import {
|
||||
destinationFiltersRefsSchema,
|
||||
transformedDestinationFiltersSchema,
|
||||
} from "../schemas/destinationFilters"
|
||||
import { accordionSchema } from "../schemas/blocks/accordion"
|
||||
import { contentSchema } from "../schemas/blocks/content"
|
||||
import { transformedDestinationFiltersSchema } from "../schemas/destinationFilters"
|
||||
import { mapLocationSchema } from "../schemas/mapLocation"
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../schemas/pageLinks"
|
||||
import { linkUnionSchema, transformPageLink } from "../schemas/pageLinks"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
import type { ImageVaultAsset } from "@scandic-hotels/common/utils/imageVault"
|
||||
@@ -131,47 +121,3 @@ export const countryPageUrlsSchema = z
|
||||
.transform(
|
||||
({ all_destination_country_page }) => all_destination_country_page.items
|
||||
)
|
||||
|
||||
/** REFS */
|
||||
const destinationCountryPageContentRefs = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
DestinationCountryPageEnum.ContentStack.blocks.Content
|
||||
),
|
||||
})
|
||||
.merge(contentRefsSchema)
|
||||
|
||||
const destinationCountryPageAccordionRefs = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
DestinationCountryPageEnum.ContentStack.blocks.Accordion
|
||||
),
|
||||
})
|
||||
.merge(accordionRefsSchema)
|
||||
|
||||
const blocksRefsSchema = z.discriminatedUnion("__typename", [
|
||||
destinationCountryPageAccordionRefs,
|
||||
destinationCountryPageContentRefs,
|
||||
])
|
||||
export const destinationCountryPageRefsSchema = z.object({
|
||||
destination_country_page: z.object({
|
||||
sidepeek_content: z
|
||||
.object({
|
||||
content: z
|
||||
.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.nullish(),
|
||||
})
|
||||
.nullish(),
|
||||
blocks: discriminatedUnionArray(blocksRefsSchema.options).nullable(),
|
||||
seo_filters: destinationFiltersRefsSchema,
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,73 +2,26 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetDestinationCountryPage,
|
||||
GetDestinationCountryPageRefs,
|
||||
} from "../../../graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql"
|
||||
import { GetDestinationCountryPage } from "../../../graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import {
|
||||
contentStackBaseWithServiceProcedure,
|
||||
contentstackExtendedProcedureUID,
|
||||
} from "../../../procedures"
|
||||
import { ApiCountry } from "../../../types/country"
|
||||
import { generateRefsResponseTag } from "../../../utils/generateTag"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { getCityPagesInput } from "./input"
|
||||
import {
|
||||
destinationCountryPageRefsSchema,
|
||||
destinationCountryPageSchema,
|
||||
} from "./output"
|
||||
import { generatePageTags, getCityPages } from "./utils"
|
||||
import { destinationCountryPageSchema } from "./output"
|
||||
import { getCityPages } from "./utils"
|
||||
|
||||
import type {
|
||||
GetDestinationCountryPageData,
|
||||
GetDestinationCountryPageRefsSchema,
|
||||
} from "../../../types/destinationCountryPage"
|
||||
import type { GetDestinationCountryPageData } from "../../../types/destinationCountryPage"
|
||||
import type { TrackingPageData } from "../../types"
|
||||
|
||||
export const destinationCountryPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const getDestinationCountryPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.destinationCountryPage.get.refs"
|
||||
)
|
||||
const metricsGetDestinationCountryPageRefs =
|
||||
getDestinationCountryPageRefsCounter.init({ lang, uid })
|
||||
|
||||
metricsGetDestinationCountryPageRefs.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const refsResponse = await request<GetDestinationCountryPageRefsSchema>(
|
||||
GetDestinationCountryPageRefs,
|
||||
variables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, uid),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
metricsGetDestinationCountryPageRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetDestinationCountryPageRefs returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedRefsData = destinationCountryPageRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
if (!validatedRefsData.success) {
|
||||
metricsGetDestinationCountryPageRefs.validationError(
|
||||
validatedRefsData.error
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetDestinationCountryPageRefs.success()
|
||||
|
||||
const tags = generatePageTags(validatedRefsData.data, lang)
|
||||
const cacheKey = generateTag(lang, uid)
|
||||
|
||||
const getDestinationCountryPageCounter = createCounter(
|
||||
"trpc.contentstack.destinationCountryPage.get"
|
||||
@@ -78,11 +31,12 @@ export const destinationCountryPageQueryRouter = router({
|
||||
|
||||
metricsGetDestinationCountryPage.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const response = await request<GetDestinationCountryPageData>(
|
||||
GetDestinationCountryPage,
|
||||
variables,
|
||||
{
|
||||
key: tags,
|
||||
key: `${cacheKey}:destinationCountryPage`,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,8 +4,7 @@ import { GetDestinationCityListData } from "../../../graphql/Query/DestinationCi
|
||||
import { GetCountryPageUrls } from "../../../graphql/Query/DestinationCountryPage/DestinationCountryPageUrl.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { ApiCountry } from "../../../types/country"
|
||||
import { DestinationCountryPageEnum } from "../../../types/destinationCountryPage"
|
||||
import { generateTag, generateTagsFromSystem } from "../../../utils/generateTag"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { getCitiesByCountry } from "../../hotels/services/getCitiesByCountry"
|
||||
import { destinationCityListDataSchema } from "../destinationCityPage/output"
|
||||
import { countryPageUrlsSchema } from "./output"
|
||||
@@ -14,60 +13,7 @@ import type { Country } from "@scandic-hotels/common/constants/country"
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type { GetDestinationCityListDataResponse } from "../../../types/destinationCityPage"
|
||||
import type {
|
||||
DestinationCountryPageRefs,
|
||||
GetCountryPageUrlsData,
|
||||
} from "../../../types/destinationCountryPage"
|
||||
import type { System } from "../schemas/system"
|
||||
|
||||
export function generatePageTags(
|
||||
validatedData: DestinationCountryPageRefs,
|
||||
lang: Lang
|
||||
): string[] {
|
||||
const connections = getConnections(validatedData)
|
||||
return [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, validatedData.destination_country_page.system.uid),
|
||||
].flat()
|
||||
}
|
||||
|
||||
export function getConnections({
|
||||
destination_country_page,
|
||||
}: DestinationCountryPageRefs) {
|
||||
const connections: System["system"][] = [destination_country_page.system]
|
||||
if (destination_country_page.blocks) {
|
||||
destination_country_page.blocks.forEach((block) => {
|
||||
switch (block.__typename) {
|
||||
case DestinationCountryPageEnum.ContentStack.blocks.Accordion: {
|
||||
if (block.accordion.length) {
|
||||
connections.push(...block.accordion.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
}
|
||||
case DestinationCountryPageEnum.ContentStack.blocks.Content:
|
||||
{
|
||||
if (block?.content?.length) {
|
||||
// TS has trouble infering the filtered types
|
||||
// @ts-ignore
|
||||
connections.push(...block.content)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
if (destination_country_page.sidepeek_content) {
|
||||
destination_country_page.sidepeek_content?.content?.embedded_itemsConnection.edges.forEach(
|
||||
({ node }) => {
|
||||
if (node.system) {
|
||||
connections.push(node.system)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
import type { GetCountryPageUrlsData } from "../../../types/destinationCountryPage"
|
||||
|
||||
export async function getCityListDataByCityIdentifier(
|
||||
lang: Lang,
|
||||
|
||||
@@ -2,10 +2,7 @@ import { z } from "zod"
|
||||
|
||||
import { DestinationOverviewPageEnum } from "../../../types/destinationOverviewPage"
|
||||
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
cardGalleryRefsSchema,
|
||||
cardGallerySchema,
|
||||
} from "../schemas/blocks/cardGallery"
|
||||
import { cardGallerySchema } from "../schemas/blocks/cardGallery"
|
||||
import { mapLocationSchema } from "../schemas/mapLocation"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
@@ -37,23 +34,3 @@ export const destinationOverviewPageSchema = z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
/** REFS */
|
||||
const destinationOverviewPageCardGalleryRef = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
DestinationOverviewPageEnum.ContentStack.blocks.CardGallery
|
||||
),
|
||||
})
|
||||
.merge(cardGalleryRefsSchema)
|
||||
|
||||
const blocksRefsSchema = z.discriminatedUnion("__typename", [
|
||||
destinationOverviewPageCardGalleryRef,
|
||||
])
|
||||
|
||||
export const destinationOverviewPageRefsSchema = z.object({
|
||||
destination_overview_page: z.object({
|
||||
blocks: discriminatedUnionArray(blocksRefsSchema.options).nullable(),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -3,37 +3,25 @@ import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
||||
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetDestinationOverviewPage,
|
||||
GetDestinationOverviewPageRefs,
|
||||
} from "../../../graphql/Query/DestinationOverviewPage/DestinationOverviewPage.graphql"
|
||||
import { GetDestinationOverviewPage } from "../../../graphql/Query/DestinationOverviewPage/DestinationOverviewPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import {
|
||||
contentstackExtendedProcedureUID,
|
||||
serviceProcedure,
|
||||
} from "../../../procedures"
|
||||
import { ApiCountry } from "../../../types/country"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
} from "../../../utils/generateTag"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { getCitiesByCountry } from "../../hotels/services/getCitiesByCountry"
|
||||
import { getCountries } from "../../hotels/services/getCountries"
|
||||
import { getHotelIdsByCityId } from "../../hotels/services/getHotelIdsByCityId"
|
||||
import { getCityPageUrls } from "../destinationCityPage/utils"
|
||||
import { getCountryPageUrls } from "../destinationCountryPage/utils"
|
||||
import {
|
||||
destinationOverviewPageRefsSchema,
|
||||
destinationOverviewPageSchema,
|
||||
} from "./output"
|
||||
import { destinationOverviewPageSchema } from "./output"
|
||||
import { getSortedDestinationsByLanguage } from "./utils"
|
||||
|
||||
import type { Country } from "@scandic-hotels/common/constants/country"
|
||||
|
||||
import type {
|
||||
GetDestinationOverviewPageData,
|
||||
GetDestinationOverviewPageRefsSchema,
|
||||
} from "../../../types/destinationOverviewPage"
|
||||
import type { GetDestinationOverviewPageData } from "../../../types/destinationOverviewPage"
|
||||
import type { City, DestinationsData } from "../../../types/destinationsData"
|
||||
import type { TrackingPageData } from "../../types"
|
||||
|
||||
@@ -41,43 +29,7 @@ export const destinationOverviewPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const getDestinationOverviewPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.destinationOverviewPage.get.refs"
|
||||
)
|
||||
const metricsGetDestinationOverviewPageRefs =
|
||||
getDestinationOverviewPageRefsCounter.init({ lang, uid })
|
||||
|
||||
metricsGetDestinationOverviewPageRefs.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const refsResponse = await request<GetDestinationOverviewPageRefsSchema>(
|
||||
GetDestinationOverviewPageRefs,
|
||||
variables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, uid),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
if (!refsResponse.data) {
|
||||
metricsGetDestinationOverviewPageRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetDestinationOverviewPageRefs returned no data",
|
||||
errorDetails: variables,
|
||||
})
|
||||
}
|
||||
|
||||
const validatedRefsData = destinationOverviewPageRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
|
||||
if (!validatedRefsData.success) {
|
||||
metricsGetDestinationOverviewPageRefs.validationError(
|
||||
validatedRefsData.error
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetDestinationOverviewPageRefs.success()
|
||||
const cacheKey = generateTag(lang, uid)
|
||||
|
||||
const getDestinationOverviewPageCounter = createCounter(
|
||||
"trpc.contentstack.destinationOverviewPage.get"
|
||||
@@ -87,11 +39,12 @@ export const destinationOverviewPageQueryRouter = router({
|
||||
|
||||
metricsGetDestinationOverviewPage.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const response = await request<GetDestinationOverviewPageData>(
|
||||
GetDestinationOverviewPage,
|
||||
variables,
|
||||
{
|
||||
key: generateTag(lang, uid),
|
||||
key: `${cacheKey}:destinationOverviewPage`,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -5,12 +5,9 @@ import { nullableStringValidator } from "@scandic-hotels/common/utils/zod/string
|
||||
|
||||
import { HotelPageEnum } from "../../../types/hotelPageEnum"
|
||||
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
activitiesCardRefSchema,
|
||||
activitiesCardSchema,
|
||||
} from "../schemas/blocks/activitiesCard"
|
||||
import { hotelFaqRefsSchema, hotelFaqSchema } from "../schemas/blocks/hotelFaq"
|
||||
import { spaPageRefSchema, spaPageSchema } from "../schemas/blocks/spaPage"
|
||||
import { activitiesCardSchema } from "../schemas/blocks/activitiesCard"
|
||||
import { hotelFaqSchema } from "../schemas/blocks/hotelFaq"
|
||||
import { spaPageSchema } from "../schemas/blocks/spaPage"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
import type { ActivitiesCard, SpaPage } from "../../../types/hotelPage"
|
||||
@@ -112,35 +109,6 @@ export const hotelPageSchema = z.object({
|
||||
})),
|
||||
})
|
||||
|
||||
/** REFS */
|
||||
const hotelPageActivitiesCardRefs = z
|
||||
.object({
|
||||
__typename: z.literal(HotelPageEnum.ContentStack.blocks.ActivitiesCard),
|
||||
})
|
||||
.merge(activitiesCardRefSchema)
|
||||
|
||||
const hotelPageSpaPageRefs = z
|
||||
.object({
|
||||
__typename: z.literal(HotelPageEnum.ContentStack.blocks.SpaPage),
|
||||
})
|
||||
.merge(spaPageRefSchema)
|
||||
|
||||
const hotelPageBlockRefsItem = z.discriminatedUnion("__typename", [
|
||||
hotelPageActivitiesCardRefs,
|
||||
hotelPageSpaPageRefs,
|
||||
])
|
||||
|
||||
export const hotelPageRefsSchema = z.object({
|
||||
hotel_page: z.object({
|
||||
content: discriminatedUnionArray(hotelPageBlockRefsItem.options).nullable(),
|
||||
faq: hotelFaqRefsSchema.nullable(),
|
||||
system: systemSchema,
|
||||
}),
|
||||
trackingProps: z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
export const hotelPageUrlsSchema = z
|
||||
.object({
|
||||
all_hotel_page: z.object({
|
||||
|
||||
@@ -4,106 +4,15 @@ import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/i
|
||||
|
||||
import { LoyaltyPageEnum } from "../../../enums/loyaltyPage"
|
||||
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
cardGridRefsSchema,
|
||||
cardsGridSchema,
|
||||
} from "../schemas/blocks/cardsGrid"
|
||||
import {
|
||||
contentRefsSchema as blockContentRefsSchema,
|
||||
contentSchema as blockContentSchema,
|
||||
} from "../schemas/blocks/content"
|
||||
import {
|
||||
dynamicContentRefsSchema,
|
||||
dynamicContentSchema as blockDynamicContentSchema,
|
||||
} from "../schemas/blocks/dynamicContent"
|
||||
import {
|
||||
shortcutsRefsSchema,
|
||||
shortcutsSchema,
|
||||
} from "../schemas/blocks/shortcuts"
|
||||
import {
|
||||
contentRefsSchema as sidebarContentRefsSchema,
|
||||
contentSchema as sidebarContentSchema,
|
||||
} from "../schemas/sidebar/content"
|
||||
import { cardsGridSchema } from "../schemas/blocks/cardsGrid"
|
||||
import { contentSchema as blockContentSchema } from "../schemas/blocks/content"
|
||||
import { dynamicContentSchema as blockDynamicContentSchema } from "../schemas/blocks/dynamicContent"
|
||||
import { shortcutsSchema } from "../schemas/blocks/shortcuts"
|
||||
import { contentSchema as sidebarContentSchema } from "../schemas/sidebar/content"
|
||||
import { dynamicContentSchema as sidebarDynamicContentSchema } from "../schemas/sidebar/dynamicContent"
|
||||
import {
|
||||
joinLoyaltyContactRefsSchema,
|
||||
joinLoyaltyContactSchema,
|
||||
} from "../schemas/sidebar/joinLoyaltyContact"
|
||||
import { joinLoyaltyContactSchema } from "../schemas/sidebar/joinLoyaltyContact"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
// LoyaltyPage Refs
|
||||
const extendedCardGridRefsSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.blocks.CardsGrid),
|
||||
})
|
||||
.merge(cardGridRefsSchema)
|
||||
|
||||
const extendedContentRefsSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.blocks.Content),
|
||||
})
|
||||
.merge(blockContentRefsSchema)
|
||||
|
||||
const extendedDynamicContentRefsSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.blocks.DynamicContent),
|
||||
})
|
||||
.merge(dynamicContentRefsSchema)
|
||||
|
||||
const extendedShortcutsRefsSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.blocks.Shortcuts),
|
||||
})
|
||||
.merge(shortcutsRefsSchema)
|
||||
|
||||
const blocksRefsSchema = z.discriminatedUnion("__typename", [
|
||||
extendedCardGridRefsSchema,
|
||||
extendedContentRefsSchema,
|
||||
extendedDynamicContentRefsSchema,
|
||||
extendedShortcutsRefsSchema,
|
||||
])
|
||||
|
||||
const contentSidebarRefsSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.sidebar.Content),
|
||||
})
|
||||
.merge(sidebarContentRefsSchema)
|
||||
|
||||
const extendedJoinLoyaltyContactRefsSchema = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
LoyaltyPageEnum.ContentStack.sidebar.JoinLoyaltyContact
|
||||
),
|
||||
})
|
||||
.merge(joinLoyaltyContactRefsSchema)
|
||||
|
||||
const sidebarRefsSchema = z.discriminatedUnion("__typename", [
|
||||
contentSidebarRefsSchema,
|
||||
extendedJoinLoyaltyContactRefsSchema,
|
||||
z.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.sidebar.DynamicContent),
|
||||
}),
|
||||
])
|
||||
|
||||
export const loyaltyPageRefsSchema = z.object({
|
||||
loyalty_page: z.object({
|
||||
blocks: discriminatedUnionArray(blocksRefsSchema.options).optional(),
|
||||
sidebar: discriminatedUnionArray(sidebarRefsSchema.options)
|
||||
.optional()
|
||||
.transform((data) => {
|
||||
if (data) {
|
||||
return data.filter(
|
||||
(block) =>
|
||||
block.__typename !==
|
||||
LoyaltyPageEnum.ContentStack.sidebar.DynamicContent
|
||||
)
|
||||
}
|
||||
return data
|
||||
}),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
// LoyaltyPage
|
||||
export const extendedCardsGridSchema = z
|
||||
.object({
|
||||
|
||||
@@ -2,78 +2,20 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetLoyaltyPage,
|
||||
GetLoyaltyPageRefs,
|
||||
} from "../../../graphql/Query/LoyaltyPage/LoyaltyPage.graphql"
|
||||
import { GetLoyaltyPage } from "../../../graphql/Query/LoyaltyPage/LoyaltyPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTagsFromAssetSystem,
|
||||
generateTagsFromSystem,
|
||||
} from "../../../utils/generateTag"
|
||||
import { loyaltyPageRefsSchema, loyaltyPageSchema } from "./output"
|
||||
import { getConnections } from "./utils"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { loyaltyPageSchema } from "./output"
|
||||
|
||||
import type {
|
||||
GetLoyaltyPageRefsSchema,
|
||||
GetLoyaltyPageSchema,
|
||||
} from "../../../types/loyaltyPage"
|
||||
import type { GetLoyaltyPageSchema } from "../../../types/loyaltyPage"
|
||||
import type { TrackingPageData } from "../../types"
|
||||
|
||||
export const loyaltyPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const getLoyaltyPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.loyaltyPage.get.refs"
|
||||
)
|
||||
const metricsGetLoyaltyPageRefs = getLoyaltyPageRefsCounter.init({
|
||||
lang,
|
||||
uid,
|
||||
})
|
||||
|
||||
metricsGetLoyaltyPageRefs.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const refsResponse = await request<GetLoyaltyPageRefsSchema>(
|
||||
GetLoyaltyPageRefs,
|
||||
variables,
|
||||
{
|
||||
key: generateRefsResponseTag(lang, uid),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
metricsGetLoyaltyPageRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "GetLoyaltyPageRefs returned no data",
|
||||
errorDetails: { ...variables },
|
||||
})
|
||||
}
|
||||
|
||||
const validatedLoyaltyPageRefs = loyaltyPageRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
if (!validatedLoyaltyPageRefs.success) {
|
||||
metricsGetLoyaltyPageRefs.validationError(validatedLoyaltyPageRefs.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetLoyaltyPageRefs.success()
|
||||
|
||||
const { connections, assetConnections } = getConnections(
|
||||
validatedLoyaltyPageRefs.data
|
||||
)
|
||||
|
||||
const tags = [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTagsFromAssetSystem(assetConnections),
|
||||
generateTag(lang, validatedLoyaltyPageRefs.data.loyalty_page.system.uid),
|
||||
].flat()
|
||||
const cacheKey = generateTag(lang, uid)
|
||||
|
||||
const getLoyaltyPageCounter = createCounter(
|
||||
"trpc.contentstack.loyaltyPage.get"
|
||||
@@ -82,11 +24,12 @@ export const loyaltyPageQueryRouter = router({
|
||||
|
||||
metricsGetLoyaltyPage.start()
|
||||
|
||||
const variables = { locale: lang, uid }
|
||||
const response = await request<GetLoyaltyPageSchema>(
|
||||
GetLoyaltyPage,
|
||||
variables,
|
||||
{
|
||||
key: tags,
|
||||
key: `${cacheKey}:loyaltyPage`,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
import { LoyaltyPageEnum } from "../../../enums/loyaltyPage"
|
||||
|
||||
import type { LoyaltyPageRefs } from "../../../types/loyaltyPage"
|
||||
import type { AssetSystem, System } from "../schemas/system"
|
||||
|
||||
export function getConnections({ loyalty_page }: LoyaltyPageRefs) {
|
||||
const connections: System["system"][] = [loyalty_page.system]
|
||||
const assetConnections: AssetSystem[] = []
|
||||
|
||||
if (loyalty_page.blocks) {
|
||||
loyalty_page.blocks.forEach((block) => {
|
||||
switch (block.__typename) {
|
||||
case LoyaltyPageEnum.ContentStack.blocks.CardsGrid:
|
||||
if (block.cards_grid.length) {
|
||||
connections.push(...block.cards_grid)
|
||||
}
|
||||
break
|
||||
case LoyaltyPageEnum.ContentStack.blocks.Content:
|
||||
if (block?.content?.length) {
|
||||
block.content.forEach((contentBlock) => {
|
||||
if ("system" in contentBlock) {
|
||||
assetConnections.push(contentBlock)
|
||||
} else {
|
||||
connections.push(contentBlock)
|
||||
}
|
||||
})
|
||||
}
|
||||
break
|
||||
case LoyaltyPageEnum.ContentStack.blocks.DynamicContent:
|
||||
if (block.dynamic_content.link) {
|
||||
connections.push(block.dynamic_content.link)
|
||||
}
|
||||
break
|
||||
case LoyaltyPageEnum.ContentStack.blocks.Shortcuts:
|
||||
if (block.shortcuts.shortcuts.length) {
|
||||
connections.push(...block.shortcuts.shortcuts.filter((c) => !!c))
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (loyalty_page.sidebar) {
|
||||
loyalty_page.sidebar.forEach((block) => {
|
||||
switch (block?.__typename) {
|
||||
case LoyaltyPageEnum.ContentStack.sidebar.Content:
|
||||
if (block?.content?.length) {
|
||||
block.content.forEach((contentBlock) => {
|
||||
if ("system" in contentBlock) {
|
||||
assetConnections.push(contentBlock)
|
||||
} else {
|
||||
connections.push(contentBlock)
|
||||
}
|
||||
})
|
||||
}
|
||||
break
|
||||
case LoyaltyPageEnum.ContentStack.sidebar.JoinLoyaltyContact:
|
||||
if (block.join_loyalty_contact?.button) {
|
||||
connections.push(block.join_loyalty_contact.button)
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return { connections, assetConnections }
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -2,12 +2,7 @@ import { z } from "zod"
|
||||
|
||||
import { MembershipLevelEnum } from "@scandic-hotels/common/constants/membershipLevels"
|
||||
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../schemas/pageLinks"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
import { linkUnionSchema, transformPageLink } from "../schemas/pageLinks"
|
||||
|
||||
export {
|
||||
BenefitReward,
|
||||
@@ -15,7 +10,6 @@ export {
|
||||
CouponReward,
|
||||
REDEEM_LOCATIONS,
|
||||
REWARD_TYPES,
|
||||
rewardRefsSchema,
|
||||
validateApiAllTiersSchema,
|
||||
validateCategorizedRewardsSchema,
|
||||
validateCmsRewardsSchema,
|
||||
@@ -65,31 +59,6 @@ const validateCmsRewardsSchema = z
|
||||
})
|
||||
.transform((data) => data.data.all_reward.items)
|
||||
|
||||
const rewardRefsSchema = z.object({
|
||||
data: z.object({
|
||||
all_reward: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
redeem_description: z
|
||||
.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
// This is primarily added in order to handle a transition
|
||||
// switching from string to RTE
|
||||
.nullable(),
|
||||
system: systemSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const REDEEM_LOCATIONS = ["Non-redeemable", "On-site", "Online"] as const
|
||||
const REWARD_CATEGORIES = [
|
||||
"Restaurants",
|
||||
|
||||
@@ -3,27 +3,14 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import * as api from "../../../api"
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetRewards as GetRewards,
|
||||
GetRewardsRef as GetRewardsRef,
|
||||
} from "../../../graphql/Query/RewardsWithRedeem.graphql"
|
||||
import { GetRewards } from "../../../graphql/Query/RewardsWithRedeem.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import {
|
||||
generateLoyaltyConfigTag,
|
||||
generateRefsResponseTag,
|
||||
} from "../../../utils/generateTag"
|
||||
import {
|
||||
rewardRefsSchema,
|
||||
validateApiAllTiersSchema,
|
||||
validateCmsRewardsSchema,
|
||||
} from "./output"
|
||||
import { generateLoyaltyConfigTag } from "../../../utils/generateTag"
|
||||
import { validateApiAllTiersSchema, validateCmsRewardsSchema } from "./output"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type {
|
||||
CMSRewardsResponse,
|
||||
GetRewardRefsSchema,
|
||||
} from "../../../types/reward"
|
||||
import type { CMSRewardsResponse } from "../../../types/reward"
|
||||
|
||||
export function getUniqueRewardIds(rewardIds: string[]) {
|
||||
const uniqueRewardIds = new Set(rewardIds)
|
||||
@@ -88,44 +75,6 @@ export async function getCmsRewards(lang: Lang, rewardIds: string[]) {
|
||||
generateLoyaltyConfigTag(lang, "reward", id)
|
||||
)
|
||||
|
||||
const getContentstackRewardAllRefsCounter = createCounter(
|
||||
"trpc.contentstack.reward.all.refs"
|
||||
)
|
||||
const metricsGetContentstackRewardAllRefs =
|
||||
getContentstackRewardAllRefsCounter.init({ lang, rewardIds })
|
||||
|
||||
metricsGetContentstackRewardAllRefs.start()
|
||||
|
||||
const refsResponse = await request<GetRewardRefsSchema>(
|
||||
GetRewardsRef,
|
||||
{
|
||||
locale: lang,
|
||||
rewardIds,
|
||||
},
|
||||
{
|
||||
key: rewardIds.map((rewardId) => generateRefsResponseTag(lang, rewardId)),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
metricsGetContentstackRewardAllRefs.noDataError()
|
||||
|
||||
throw notFoundError({
|
||||
message: "GetRewardsRef returned no data",
|
||||
errorDetails: { lang, rewardIds },
|
||||
})
|
||||
}
|
||||
|
||||
const validatedRefsData = rewardRefsSchema.safeParse(refsResponse)
|
||||
|
||||
if (!validatedRefsData.success) {
|
||||
metricsGetContentstackRewardAllRefs.validationError(validatedRefsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetContentstackRewardAllRefs.success()
|
||||
|
||||
const getContentstackRewardAllCounter = createCounter(
|
||||
"trpc.contentstack.reward.all"
|
||||
)
|
||||
@@ -134,6 +83,8 @@ export async function getCmsRewards(lang: Lang, rewardIds: string[]) {
|
||||
rewardIds,
|
||||
})
|
||||
|
||||
metricsGetContentstackRewardAll.start()
|
||||
|
||||
const cmsRewardsResponse = await request<CMSRewardsResponse>(
|
||||
GetRewards,
|
||||
{
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../pageLinks"
|
||||
import { linkUnionSchema, transformPageLink } from "../pageLinks"
|
||||
import { sysAssetSchema } from "./sysAsset"
|
||||
|
||||
export const embeddedContentSchema = z.union([linkUnionSchema, sysAssetSchema])
|
||||
@@ -117,95 +113,3 @@ export const accordionSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
export const globalAccordionConnectionRefs = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
questions: z.array(
|
||||
z.object({
|
||||
answer: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
export const specificAccordionConnectionRefs = z.object({
|
||||
questions: z.array(
|
||||
z.object({
|
||||
answer: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
export const accordionRefsSchema = z.object({
|
||||
accordion: z
|
||||
.object({
|
||||
accordions: z.array(
|
||||
z.object({
|
||||
__typename: z.nativeEnum(AccordionEnum),
|
||||
global_accordion: z
|
||||
.object({
|
||||
global_accordionConnection: globalAccordionConnectionRefs,
|
||||
})
|
||||
.optional(),
|
||||
specific_accordion: specificAccordionConnectionRefs.optional(),
|
||||
})
|
||||
),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data.accordions.flatMap((accordion) => {
|
||||
switch (accordion.__typename) {
|
||||
case AccordionEnum.CampaignPageBlocksAccordionBlockAccordionsGlobalAccordion:
|
||||
case AccordionEnum.ContentPageBlocksAccordionBlockAccordionsGlobalAccordion:
|
||||
case AccordionEnum.DestinationCityPageBlocksAccordionBlockAccordionsGlobalAccordion:
|
||||
case AccordionEnum.DestinationCountryPageBlocksAccordionBlockAccordionsGlobalAccordion:
|
||||
case AccordionEnum.DestinationFilterBlocksAccordionBlockAccordionsGlobalAccordion:
|
||||
case AccordionEnum.PromoCampaignPageBlocksAccordionBlockAccordionsGlobalAccordion:
|
||||
return (
|
||||
accordion.global_accordion?.global_accordionConnection.edges.flatMap(
|
||||
({ node: accordionConnection }) => {
|
||||
return accordionConnection.questions.flatMap((question) =>
|
||||
question.answer.embedded_itemsConnection.edges.flatMap(
|
||||
({ node }) => node.system
|
||||
)
|
||||
)
|
||||
}
|
||||
) || []
|
||||
)
|
||||
case AccordionEnum.CampaignPageBlocksAccordionBlockAccordionsSpecificAccordion:
|
||||
case AccordionEnum.DestinationCityPageBlocksAccordionBlockAccordionsSpecificAccordion:
|
||||
case AccordionEnum.DestinationCountryPageBlocksAccordionBlockAccordionsSpecificAccordion:
|
||||
case AccordionEnum.DestinationFilterBlocksAccordionBlockAccordionsSpecificAccordion:
|
||||
case AccordionEnum.PromoCampaignPageBlocksAccordionBlockAccordionsSpecificAccordion:
|
||||
return (
|
||||
accordion.specific_accordion?.questions.flatMap((question) =>
|
||||
question.answer.embedded_itemsConnection.edges.flatMap(
|
||||
({ node }) => node.system
|
||||
)
|
||||
) || []
|
||||
)
|
||||
default:
|
||||
return []
|
||||
}
|
||||
})
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -4,12 +4,7 @@ import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/i
|
||||
import { removeMultipleSlashes } from "@scandic-hotels/common/utils/url"
|
||||
|
||||
import { HotelPageEnum } from "../../../../types/hotelPageEnum"
|
||||
import {
|
||||
collectionPageRefSchema,
|
||||
collectionPageSchema,
|
||||
contentPageRefSchema,
|
||||
contentPageSchema,
|
||||
} from "../pageLinks"
|
||||
import { collectionPageSchema, contentPageSchema } from "../pageLinks"
|
||||
|
||||
export const activitiesCardSchema = z.object({
|
||||
typename: z
|
||||
@@ -70,26 +65,3 @@ export const activitiesCardSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
export const activitiesCardRefSchema = z.object({
|
||||
upcoming_activities_card: z
|
||||
.object({
|
||||
hotel_page_activities_content_pageConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
contentPageRefSchema,
|
||||
collectionPageRefSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
return (
|
||||
data.hotel_page_activities_content_pageConnection.edges.flatMap(
|
||||
({ node }) => node.system
|
||||
) || []
|
||||
)
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -4,7 +4,6 @@ import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/i
|
||||
import { removeMultipleSlashes } from "@scandic-hotels/common/utils/url"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { campaignPageRefSchema, promoCampaignPageRefSchema } from "../pageLinks"
|
||||
|
||||
export const campaignPageCardSchema = z.object({
|
||||
image: transformedImageVaultAssetSchema,
|
||||
@@ -66,18 +65,3 @@ export const allCampaignsSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
export const allCampaignsRefsSchema = z.object({
|
||||
all_campaigns: z.object({
|
||||
campaignsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
campaignPageRefSchema,
|
||||
promoCampaignPageRefSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import {
|
||||
contentCardRefSchema,
|
||||
contentCardSchema,
|
||||
transformContentCard,
|
||||
} from "./cards/contentCard"
|
||||
import { contentCardSchema, transformContentCard } from "./cards/contentCard"
|
||||
import { buttonSchema } from "./utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "./utils/linkConnection"
|
||||
|
||||
export const cardGallerySchema = z.object({
|
||||
typename: z
|
||||
@@ -77,24 +72,3 @@ export const cardGallerySchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
export const cardGalleryRefsSchema = z.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.CardGallery)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.CardGallery),
|
||||
card_gallery: z.object({
|
||||
card_groups: z.array(
|
||||
z.object({
|
||||
cardsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: contentCardRefSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
),
|
||||
link: linkConnectionRefsSchema.optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -5,7 +5,6 @@ import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/i
|
||||
import { CardsEnum } from "../../../../../types/cardsEnum"
|
||||
import { systemSchema } from "../../system"
|
||||
import { buttonSchema } from "../utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "../utils/linkConnection"
|
||||
|
||||
export const contentCardSchema = z.object({
|
||||
__typename: z.literal(CardsEnum.ContentCard),
|
||||
@@ -19,12 +18,6 @@ export const contentCardSchema = z.object({
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export const contentCardRefSchema = z.object({
|
||||
__typename: z.literal(CardsEnum.ContentCard),
|
||||
card_link: linkConnectionRefsSchema,
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export function transformContentCard(card: typeof contentCardSchema._type) {
|
||||
// Return null if image or image URL is missing
|
||||
if (!card.image?.url) return null
|
||||
|
||||
@@ -6,7 +6,6 @@ import { CardsEnum } from "../../../../../types/cardsEnum"
|
||||
import { systemSchema } from "../../system"
|
||||
import { getInfoCardThemeFromDeprecatedCardTheme } from "../cardsGrid"
|
||||
import { buttonSchema } from "../utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "../utils/linkConnection"
|
||||
|
||||
const INFO_CARD_WITH_IMAGE_THEMES = [
|
||||
"one",
|
||||
@@ -62,10 +61,3 @@ export function transformInfoCardWithImageBlock(
|
||||
system: card.system,
|
||||
}
|
||||
}
|
||||
|
||||
export const infoCardWithImageBlockRefsSchema = z.object({
|
||||
__typename: z.literal(CardsEnum.InfoCardWithImage),
|
||||
primary_button: linkConnectionRefsSchema,
|
||||
secondary_button: linkConnectionRefsSchema,
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
@@ -5,7 +5,6 @@ import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/i
|
||||
import { CardsEnum } from "../../../../../types/cardsEnum"
|
||||
import { systemSchema } from "../../system"
|
||||
import { buttonSchema } from "../utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "../utils/linkConnection"
|
||||
|
||||
export const loyaltyCardBlockSchema = z.object({
|
||||
__typename: z.literal(CardsEnum.LoyaltyCard),
|
||||
@@ -17,9 +16,3 @@ export const loyaltyCardBlockSchema = z.object({
|
||||
system: systemSchema,
|
||||
title: z.string().optional(),
|
||||
})
|
||||
|
||||
export const loyaltyCardBlockRefsSchema = z.object({
|
||||
__typename: z.literal(CardsEnum.LoyaltyCard),
|
||||
link: linkConnectionRefsSchema,
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
@@ -21,7 +21,6 @@ import { systemSchema } from "../../system"
|
||||
import { imageContainerSchema } from "../imageContainer"
|
||||
import { sysAssetSchema } from "../sysAsset"
|
||||
import { buttonSchema } from "../utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "../utils/linkConnection"
|
||||
|
||||
export const teaserCardBlockSchema = z.object({
|
||||
__typename: z.literal(CardsEnum.TeaserCard),
|
||||
@@ -118,10 +117,3 @@ export function transformTeaserCardBlock(
|
||||
system: card.system,
|
||||
}
|
||||
}
|
||||
|
||||
export const teaserCardBlockRefsSchema = z.object({
|
||||
__typename: z.literal(CardsEnum.TeaserCard),
|
||||
primary_button: linkConnectionRefsSchema,
|
||||
secondary_button: linkConnectionRefsSchema,
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
@@ -10,21 +10,15 @@ import {
|
||||
} from "../../../../types/cardsGridEnum"
|
||||
import { systemSchema } from "../system"
|
||||
import {
|
||||
infoCardWithImageBlockRefsSchema,
|
||||
infoCardWithImageBlockSchema,
|
||||
transformInfoCardWithImageBlock,
|
||||
} from "./cards/infoCardWithImage"
|
||||
import { loyaltyCardBlockSchema } from "./cards/loyaltyCard"
|
||||
import {
|
||||
loyaltyCardBlockRefsSchema,
|
||||
loyaltyCardBlockSchema,
|
||||
} from "./cards/loyaltyCard"
|
||||
import {
|
||||
teaserCardBlockRefsSchema,
|
||||
teaserCardBlockSchema,
|
||||
transformTeaserCardBlock,
|
||||
} from "./cards/teaserCard"
|
||||
import { buttonSchema } from "./utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "./utils/linkConnection"
|
||||
|
||||
export const infoCardBlockSchema = z.object({
|
||||
__typename: z.literal(CardsGridEnum.cards.InfoCard),
|
||||
@@ -140,67 +134,6 @@ export const cardsGridSchema = z.object({
|
||||
}),
|
||||
})
|
||||
|
||||
export const infoCardBlockRefsSchema = z.object({
|
||||
__typename: z.literal(CardsGridEnum.cards.InfoCard),
|
||||
primary_button: linkConnectionRefsSchema,
|
||||
secondary_button: linkConnectionRefsSchema,
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export function transformCardBlockRefs(
|
||||
card:
|
||||
| typeof infoCardBlockRefsSchema._type
|
||||
| typeof teaserCardBlockRefsSchema._type
|
||||
| typeof infoCardWithImageBlockRefsSchema._type
|
||||
) {
|
||||
const cards = [card.system]
|
||||
if (card.primary_button) {
|
||||
cards.push(card.primary_button)
|
||||
}
|
||||
if (card.secondary_button) {
|
||||
cards.push(card.secondary_button)
|
||||
}
|
||||
return cards
|
||||
}
|
||||
|
||||
export const cardGridRefsSchema = z.object({
|
||||
cards_grid: z
|
||||
.object({
|
||||
cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
infoCardBlockRefsSchema,
|
||||
loyaltyCardBlockRefsSchema,
|
||||
teaserCardBlockRefsSchema,
|
||||
infoCardWithImageBlockRefsSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
link: linkConnectionRefsSchema.nullish(),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data.cardConnection.edges
|
||||
.map(({ node }) => {
|
||||
if (
|
||||
node.__typename === CardsGridEnum.cards.InfoCard ||
|
||||
node.__typename === CardsGridEnum.cards.TeaserCard ||
|
||||
node.__typename === CardsGridEnum.cards.InfoCardWithImage
|
||||
) {
|
||||
return transformCardBlockRefs(node)
|
||||
} else {
|
||||
const loyaltyCards = [node.system]
|
||||
if (node.link) {
|
||||
loyaltyCards.push(node.link)
|
||||
}
|
||||
return loyaltyCards
|
||||
}
|
||||
})
|
||||
.flat()
|
||||
}),
|
||||
})
|
||||
|
||||
export function getInfoCardThemeFromDeprecatedCardTheme(theme?: string | null) {
|
||||
if (!theme) {
|
||||
return null
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import {
|
||||
contentCardRefSchema,
|
||||
contentCardSchema,
|
||||
transformContentCard,
|
||||
} from "./cards/contentCard"
|
||||
import { contentCardSchema, transformContentCard } from "./cards/contentCard"
|
||||
import { buttonSchema } from "./utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "./utils/linkConnection"
|
||||
|
||||
const commonFields = {
|
||||
heading: z.string().optional(),
|
||||
@@ -135,24 +130,3 @@ export const carouselCardsSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
export const carouselCardsRefsSchema = z.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.CarouselCards)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.CarouselCards),
|
||||
carousel_cards: z.object({
|
||||
card_groups: z.array(
|
||||
z.object({
|
||||
cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: contentCardRefSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
),
|
||||
link: linkConnectionRefsSchema.nullish(),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { ContentEnum } from "../../../../types/content"
|
||||
import {
|
||||
rawLinkRefsUnionSchema,
|
||||
rawLinkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../pageLinks"
|
||||
import {
|
||||
imageContainerRefsSchema,
|
||||
imageContainerSchema,
|
||||
} from "./imageContainer"
|
||||
import { sysAssetRefsSchema, sysAssetSchema } from "./sysAsset"
|
||||
import { rawLinkUnionSchema, transformPageLink } from "../pageLinks"
|
||||
import { imageContainerSchema } from "./imageContainer"
|
||||
import { sysAssetSchema } from "./sysAsset"
|
||||
|
||||
export const contentSchema = z.object({
|
||||
typename: z
|
||||
@@ -50,39 +42,3 @@ export const contentSchema = z.object({
|
||||
return data?.content
|
||||
}),
|
||||
})
|
||||
|
||||
export const contentRefsSchema = z.object({
|
||||
content: z
|
||||
.object({
|
||||
content: z
|
||||
.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
sysAssetRefsSchema,
|
||||
imageContainerRefsSchema,
|
||||
...rawLinkRefsUnionSchema.options,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.nullish(),
|
||||
})
|
||||
.nullish()
|
||||
.transform((data) => {
|
||||
return data?.content?.embedded_itemsConnection.edges
|
||||
.map(({ node }) => {
|
||||
switch (node.__typename) {
|
||||
case ContentEnum.blocks.SysAsset:
|
||||
return node.system && (node.permanent_url || node.url)
|
||||
? { system: node.system, url: node.permanent_url || node.url }
|
||||
: null
|
||||
default:
|
||||
return node.system
|
||||
}
|
||||
})
|
||||
.filter((node) => !!node)
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,11 +2,7 @@ import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { DynamicContentEnum } from "../../../../types/dynamicContent"
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../pageLinks"
|
||||
import { linkUnionSchema, transformPageLink } from "../pageLinks"
|
||||
|
||||
export const dynamicContentSchema = z.object({
|
||||
typename: z
|
||||
@@ -47,24 +43,3 @@ export const dynamicContentSchema = z.object({
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const dynamicContentRefsSchema = z.object({
|
||||
dynamic_content: z.object({
|
||||
link: z
|
||||
.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (data.linkConnection?.edges.length) {
|
||||
return data.linkConnection.edges[0].node.system
|
||||
}
|
||||
return null
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,7 +2,6 @@ import { z } from "zod"
|
||||
|
||||
import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/imageVault"
|
||||
|
||||
import * as pageLinks from "../../../../routers/contentstack/schemas/pageLinks"
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { systemSchema } from "../system"
|
||||
import { buttonSchema } from "./utils/buttonLinkSchema"
|
||||
@@ -41,24 +40,3 @@ export const fullWidthCampaignBlockSchema = z
|
||||
.default(BlocksEnums.block.FullWidthCampaign),
|
||||
})
|
||||
.merge(fullWidthCampaignSchema)
|
||||
|
||||
export const fullWidthCampaignBlockRefsSchema = z.object({
|
||||
full_width_campaign: z.object({
|
||||
full_width_campaignConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageRefSchema,
|
||||
pageLinks.contentPageRefSchema,
|
||||
pageLinks.loyaltyPageRefSchema,
|
||||
pageLinks.collectionPageRefSchema,
|
||||
pageLinks.hotelPageRefSchema,
|
||||
pageLinks.destinationCityPageRefSchema,
|
||||
pageLinks.destinationCountryPageRefSchema,
|
||||
pageLinks.destinationOverviewPageRefSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { HotelPageEnum } from "../../../../types/hotelPageEnum"
|
||||
import {
|
||||
accordionItemsSchema,
|
||||
globalAccordionConnectionRefs,
|
||||
specificAccordionConnectionRefs,
|
||||
} from "./accordion"
|
||||
import { accordionItemsSchema } from "./accordion"
|
||||
|
||||
export const hotelFaqSchema = z
|
||||
.object({
|
||||
@@ -43,33 +38,3 @@ export const hotelFaqSchema = z
|
||||
array.push(data.specific_faq?.questions || [])
|
||||
return { ...data, accordions: array.flat(2) }
|
||||
})
|
||||
|
||||
export const hotelFaqRefsSchema = z
|
||||
.object({
|
||||
__typename: z
|
||||
.literal(HotelPageEnum.ContentStack.blocks.Faq)
|
||||
.optional()
|
||||
.default(HotelPageEnum.ContentStack.blocks.Faq),
|
||||
global_faqConnection: globalAccordionConnectionRefs.optional(),
|
||||
specific_faq: specificAccordionConnectionRefs.optional().nullable(),
|
||||
})
|
||||
.transform((data) => {
|
||||
const array = []
|
||||
array.push(
|
||||
data.global_faqConnection?.edges.flatMap(({ node: faqConnection }) => {
|
||||
return faqConnection.questions.flatMap((question) =>
|
||||
question.answer.embedded_itemsConnection.edges.flatMap(
|
||||
({ node }) => node.system
|
||||
)
|
||||
)
|
||||
}) || []
|
||||
)
|
||||
array.push(
|
||||
data.specific_faq?.questions.flatMap((question) =>
|
||||
question.answer.embedded_itemsConnection.edges.flatMap(
|
||||
({ node }) => node.system
|
||||
)
|
||||
) || []
|
||||
)
|
||||
return array.flat(2)
|
||||
})
|
||||
|
||||
@@ -12,8 +12,3 @@ export const imageContainerSchema = z.object({
|
||||
system: systemSchema,
|
||||
title: z.string().optional(),
|
||||
})
|
||||
|
||||
export const imageContainerRefsSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.ImageContainer),
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
@@ -4,7 +4,6 @@ import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/i
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { buttonSchema } from "./utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "./utils/linkConnection"
|
||||
|
||||
export const joinScandicFriendsSchema = z.object({
|
||||
join_scandic_friends: z.object({
|
||||
@@ -28,9 +27,3 @@ export const joinScandicFriendsBlockSchema = z
|
||||
.default(BlocksEnums.block.JoinScandicFriends),
|
||||
})
|
||||
.merge(joinScandicFriendsSchema)
|
||||
|
||||
export const joinScandicFriendsBlockRefsSchema = z.object({
|
||||
join_scandic_friends: z.object({
|
||||
primary_button: linkConnectionRefsSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { systemSchema } from "../system"
|
||||
|
||||
export const jotformSchema = z.object({
|
||||
typename: z
|
||||
@@ -24,19 +23,3 @@ export const jotformSchema = z.object({
|
||||
return data.formConnection.edges[0]?.node || null
|
||||
}),
|
||||
})
|
||||
|
||||
export const jotformRefsSchema = z.object({
|
||||
jotform: z
|
||||
.object({
|
||||
formConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({ system: systemSchema }),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data.formConnection.edges[0]?.node || null
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../pageLinks"
|
||||
import { linkUnionSchema, transformPageLink } from "../pageLinks"
|
||||
|
||||
export const shortcutsBlockSchema = z.object({
|
||||
shortcuts: z
|
||||
@@ -91,27 +87,3 @@ export const shortcutsSchema = z
|
||||
.default(BlocksEnums.block.Shortcuts),
|
||||
})
|
||||
.merge(shortcutsBlockSchema)
|
||||
|
||||
export const shortcutsRefsSchema = z.object({
|
||||
shortcuts: z.object({
|
||||
shortcuts: z
|
||||
.array(
|
||||
z.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.transform((data) =>
|
||||
data
|
||||
.map((shortcut) => {
|
||||
return shortcut.linkConnection.edges.map(({ node }) => node.system)
|
||||
})
|
||||
.flat()
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -3,7 +3,6 @@ import { z } from "zod"
|
||||
import { removeMultipleSlashes } from "@scandic-hotels/common/utils/url"
|
||||
|
||||
import { HotelPageEnum } from "../../../../types/hotelPageEnum"
|
||||
import { collectionPageRefSchema, contentPageRefSchema } from "../pageLinks"
|
||||
|
||||
export const spaPageSchema = z.object({
|
||||
typename: z
|
||||
@@ -46,22 +45,3 @@ export const spaPageSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
export const spaPageRefSchema = z.object({
|
||||
spa_page: z
|
||||
.object({
|
||||
pageConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
contentPageRefSchema,
|
||||
collectionPageRefSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data.pageConnection.edges.flatMap(({ node }) => node.system) || []
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -31,13 +31,3 @@ export const sysAssetSchema = z.object({
|
||||
.nullish()
|
||||
.transform((val) => (val === "Permanent URL Not Defined!" ? null : val)), // ContentStack returns this string when permanent_url is not defined
|
||||
})
|
||||
|
||||
export const sysAssetRefsSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.SysAsset),
|
||||
url: z.string().nullish(),
|
||||
permanent_url: z
|
||||
.string()
|
||||
.nullish()
|
||||
.transform((val) => (val === "Permanent URL Not Defined!" ? null : val)), // ContentStack returns this string when permanent_url is not defined
|
||||
system: assetSystemSchema.nullish(),
|
||||
})
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { ContentEnum } from "../../../../types/content"
|
||||
import {
|
||||
rawLinkRefsUnionSchema,
|
||||
rawLinkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../pageLinks"
|
||||
import { sysAssetRefsSchema, sysAssetSchema } from "./sysAsset"
|
||||
|
||||
import type { linkUnionSchema } from "../pageLinks"
|
||||
import { rawLinkUnionSchema, transformPageLink } from "../pageLinks"
|
||||
import { sysAssetSchema } from "./sysAsset"
|
||||
|
||||
export const textColsSchema = z.object({
|
||||
typename: z
|
||||
@@ -45,39 +38,3 @@ export const textColsSchema = z.object({
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
type Refs = {
|
||||
node: z.TypeOf<typeof linkUnionSchema>
|
||||
}
|
||||
|
||||
export const textColsRefsSchema = z.object({
|
||||
text_cols: z
|
||||
.object({
|
||||
columns: z.array(
|
||||
z.object({
|
||||
text: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
sysAssetRefsSchema,
|
||||
...rawLinkRefsUnionSchema.options,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data.columns
|
||||
.map((column) => {
|
||||
const filtered = column.text.embedded_itemsConnection.edges.filter(
|
||||
(block) => block.node.__typename !== ContentEnum.blocks.SysAsset
|
||||
) as unknown as Refs[] // TS issue with filtered out types
|
||||
return filtered.map(({ node }) => node.system)
|
||||
})
|
||||
.flat()
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,11 +2,7 @@ import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { UspGridEnum } from "../../../../types/uspGrid"
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../pageLinks"
|
||||
import { linkUnionSchema, transformPageLink } from "../pageLinks"
|
||||
|
||||
const uspCardSchema = z.object({
|
||||
icon: UspGridEnum.uspIcons,
|
||||
@@ -53,39 +49,3 @@ export const uspGridSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
export const uspGridRefsSchema = z.object({
|
||||
usp_grid: z
|
||||
.object({
|
||||
cardsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
usp_card: z.array(
|
||||
z.object({
|
||||
text: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data.cardsConnection.edges.flatMap(({ node }) =>
|
||||
node.usp_card.flatMap((card) =>
|
||||
card.text.embedded_itemsConnection.edges.map(
|
||||
({ node }) => node.system
|
||||
)
|
||||
)
|
||||
)
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { linkRefsUnionSchema } from "../../pageLinks"
|
||||
|
||||
export const linkConnectionRefsSchema = z
|
||||
.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (!data.linkConnection.edges.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return data.linkConnection.edges[0].node?.system
|
||||
})
|
||||
@@ -1,14 +1,9 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { transformedVideoSchema, videoRefSchema } from "../video"
|
||||
import { transformedVideoSchema } from "../video"
|
||||
|
||||
export const videoBlockSchema = z.object({
|
||||
typename: z.literal(BlocksEnums.block.Video).default(BlocksEnums.block.Video),
|
||||
video: transformedVideoSchema,
|
||||
})
|
||||
|
||||
export const videoBlockRefsSchema = z.object({
|
||||
typename: z.literal(BlocksEnums.block.Video).default(BlocksEnums.block.Video),
|
||||
video: videoRefSchema,
|
||||
})
|
||||
|
||||
@@ -3,8 +3,7 @@ import { z } from "zod"
|
||||
import { logger } from "@scandic-hotels/common/logger"
|
||||
|
||||
import { BlocksEnums } from "../../../../types/blocksEnum"
|
||||
import { systemSchema } from "../system"
|
||||
import { transformedVideoSchema, videoRefSchema } from "../video"
|
||||
import { transformedVideoSchema } from "../video"
|
||||
|
||||
const cardStyleSchema = z
|
||||
.string()
|
||||
@@ -86,32 +85,3 @@ export const videoCardSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
const videoCardRefSchema = z.object({
|
||||
video: videoRefSchema,
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export const videoCardRefsSchema = z.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.VideoCard)
|
||||
.default(BlocksEnums.block.VideoCard),
|
||||
video_card: z
|
||||
.object({
|
||||
video_cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: videoCardRefSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
const videoCard = data.video_cardConnection.edges[0]?.node
|
||||
if (!videoCard?.video) {
|
||||
return null
|
||||
}
|
||||
|
||||
return videoCard
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -7,7 +7,6 @@ import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import { hotelFilterSchema } from "../../hotels/filters/output"
|
||||
import { accordionSchema } from "./blocks/accordion"
|
||||
import { contentSchema } from "./blocks/content"
|
||||
import { systemSchema } from "./system"
|
||||
|
||||
export const destinationFilterBlockContent = z
|
||||
.object({
|
||||
@@ -50,22 +49,6 @@ export const transformedDestinationFiltersSchema =
|
||||
transformDestinationFiltersResponse(data)
|
||||
)
|
||||
|
||||
export const destinationFiltersRefsSchema = z
|
||||
.array(
|
||||
z.object({
|
||||
filterConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.nullish()
|
||||
|
||||
export function transformDestinationFiltersResponse(
|
||||
data: typeof destinationFiltersSchema._type
|
||||
) {
|
||||
|
||||
@@ -5,7 +5,3 @@ import { DynamicContentEnum } from "../../../../types/dynamicContent"
|
||||
export const dynamicContentSchema = z.object({
|
||||
component: z.enum(DynamicContentEnum.Headers.enums).nullish(),
|
||||
})
|
||||
|
||||
export const dynamicContentRefsSchema = z.object({
|
||||
component: z.enum(DynamicContentEnum.Headers.enums).nullish(),
|
||||
})
|
||||
|
||||
@@ -2,12 +2,7 @@ import { z } from "zod"
|
||||
|
||||
import { nullableStringValidator } from "@scandic-hotels/common/utils/zod/stringValidator"
|
||||
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
transformPageLink,
|
||||
transformPageLinkRef,
|
||||
} from "./pageLinks"
|
||||
import { linkUnionSchema, transformPageLink } from "./pageLinks"
|
||||
|
||||
const titleSchema = z.object({
|
||||
title: nullableStringValidator,
|
||||
@@ -45,28 +40,3 @@ export const linkAndTitleSchema = z.intersection(
|
||||
linkConnectionSchema,
|
||||
titleSchema
|
||||
)
|
||||
|
||||
export const linkConnectionRefs = z
|
||||
.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: linkRefsUnionSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (data.linkConnection.edges.length) {
|
||||
const linkNode = data.linkConnection.edges[0].node
|
||||
if (linkNode) {
|
||||
const link = transformPageLinkRef(linkNode)
|
||||
if (link) {
|
||||
return {
|
||||
link,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return { link: null }
|
||||
})
|
||||
|
||||
@@ -19,11 +19,6 @@ export const accountPageSchema = z
|
||||
})
|
||||
.merge(pageLinkSchema)
|
||||
|
||||
export const accountPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.AccountPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const extendedPageLinkSchema = pageLinkSchema.merge(
|
||||
z.object({
|
||||
web: z
|
||||
@@ -40,121 +35,66 @@ export const campaignOverviewPageSchema = z
|
||||
})
|
||||
.merge(extendedPageLinkSchema)
|
||||
|
||||
export const campaignOverviewPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.CampaignOverviewPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const collectionPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.CollectionPage),
|
||||
})
|
||||
.merge(extendedPageLinkSchema)
|
||||
|
||||
export const collectionPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.CollectionPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const contentPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.ContentPage),
|
||||
})
|
||||
.merge(extendedPageLinkSchema)
|
||||
|
||||
export const contentPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.ContentPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const destinationCityPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.DestinationCityPage),
|
||||
})
|
||||
.merge(pageLinkSchema)
|
||||
|
||||
export const destinationCityPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.DestinationCityPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const campaignPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.CampaignPage),
|
||||
})
|
||||
.merge(pageLinkSchema)
|
||||
|
||||
export const campaignPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.CampaignPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const destinationCountryPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.DestinationCountryPage),
|
||||
})
|
||||
.merge(pageLinkSchema)
|
||||
|
||||
export const destinationCountryPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.DestinationCountryPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const destinationOverviewPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.DestinationOverviewPage),
|
||||
})
|
||||
.merge(pageLinkSchema)
|
||||
|
||||
export const destinationOverviewPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.DestinationOverviewPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const hotelPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.HotelPage),
|
||||
})
|
||||
.merge(pageLinkSchema)
|
||||
|
||||
export const hotelPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.HotelPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const loyaltyPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.LoyaltyPage),
|
||||
})
|
||||
.merge(extendedPageLinkSchema)
|
||||
|
||||
export const loyaltyPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.LoyaltyPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const startPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.StartPage),
|
||||
})
|
||||
.merge(pageLinkSchema)
|
||||
|
||||
export const startPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.StartPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const promoCampaignPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.PromoCampaignPage),
|
||||
})
|
||||
.merge(pageLinkSchema)
|
||||
|
||||
export const promoCampaignPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.PromoCampaignPage),
|
||||
system: systemSchema.nullable(),
|
||||
})
|
||||
|
||||
export const rawLinkUnionSchema = z.discriminatedUnion("__typename", [
|
||||
accountPageSchema,
|
||||
campaignOverviewPageSchema,
|
||||
@@ -263,55 +203,3 @@ export const internalOrExternalLinkSchema = z
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export const rawLinkRefsUnionSchema = z.discriminatedUnion("__typename", [
|
||||
accountPageRefSchema,
|
||||
campaignOverviewPageRefSchema,
|
||||
campaignPageRefSchema,
|
||||
collectionPageRefSchema,
|
||||
contentPageRefSchema,
|
||||
destinationCityPageRefSchema,
|
||||
destinationCountryPageRefSchema,
|
||||
destinationOverviewPageRefSchema,
|
||||
hotelPageRefSchema,
|
||||
loyaltyPageRefSchema,
|
||||
startPageRefSchema,
|
||||
promoCampaignPageRefSchema,
|
||||
])
|
||||
|
||||
export const linkRefsUnionSchema = safeUnion(rawLinkRefsUnionSchema)
|
||||
|
||||
type RefData =
|
||||
| z.output<typeof accountPageRefSchema>
|
||||
| z.output<typeof campaignOverviewPageRefSchema>
|
||||
| z.output<typeof campaignPageRefSchema>
|
||||
| z.output<typeof collectionPageRefSchema>
|
||||
| z.output<typeof contentPageRefSchema>
|
||||
| z.output<typeof destinationCityPageRefSchema>
|
||||
| z.output<typeof destinationCountryPageRefSchema>
|
||||
| z.output<typeof destinationOverviewPageRefSchema>
|
||||
| z.output<typeof hotelPageRefSchema>
|
||||
| z.output<typeof loyaltyPageRefSchema>
|
||||
| z.output<typeof startPageRefSchema>
|
||||
| z.output<typeof promoCampaignPageRefSchema>
|
||||
| Object
|
||||
|
||||
export function transformPageLinkRef(data: RefData) {
|
||||
if (data && "__typename" in data) {
|
||||
switch (data.__typename) {
|
||||
case ContentEnum.blocks.AccountPage:
|
||||
case ContentEnum.blocks.CampaignOverviewPage:
|
||||
case ContentEnum.blocks.CampaignPage:
|
||||
case ContentEnum.blocks.CollectionPage:
|
||||
case ContentEnum.blocks.ContentPage:
|
||||
case ContentEnum.blocks.DestinationCityPage:
|
||||
case ContentEnum.blocks.DestinationCountryPage:
|
||||
case ContentEnum.blocks.DestinationOverviewPage:
|
||||
case ContentEnum.blocks.HotelPage:
|
||||
case ContentEnum.blocks.LoyaltyPage:
|
||||
case ContentEnum.blocks.StartPage:
|
||||
case ContentEnum.blocks.PromoCampaignPage:
|
||||
return data.system
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { ContentEnum } from "../../../../types/content"
|
||||
import { SidebarEnums } from "../../../../types/sidebar"
|
||||
import {
|
||||
imageContainerRefsSchema,
|
||||
imageContainerSchema,
|
||||
} from "../blocks/imageContainer"
|
||||
import { sysAssetRefsSchema, sysAssetSchema } from "../blocks/sysAsset"
|
||||
import {
|
||||
rawLinkRefsUnionSchema,
|
||||
rawLinkUnionSchema,
|
||||
transformPageLink,
|
||||
} from "../pageLinks"
|
||||
import { imageContainerSchema } from "../blocks/imageContainer"
|
||||
import { sysAssetSchema } from "../blocks/sysAsset"
|
||||
import { rawLinkUnionSchema, transformPageLink } from "../pageLinks"
|
||||
|
||||
export const contentSchema = z.object({
|
||||
typename: z
|
||||
@@ -50,40 +42,3 @@ export const contentSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
const actualRefs = z.discriminatedUnion("__typename", [
|
||||
imageContainerRefsSchema,
|
||||
...rawLinkRefsUnionSchema.options,
|
||||
])
|
||||
|
||||
export const contentRefsSchema = z.object({
|
||||
content: z
|
||||
.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
sysAssetRefsSchema,
|
||||
...actualRefs.options,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data?.content?.embedded_itemsConnection.edges
|
||||
.map(({ node }) => {
|
||||
switch (node.__typename) {
|
||||
case ContentEnum.blocks.SysAsset:
|
||||
return node.system && (node.permanent_url || node.url)
|
||||
? { system: node.system, url: node.permanent_url || node.url }
|
||||
: null
|
||||
default:
|
||||
return node.system
|
||||
}
|
||||
})
|
||||
.filter((node) => !!node)
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -3,7 +3,6 @@ import { z } from "zod"
|
||||
import { JoinLoyaltyContactEnums } from "../../../../types/joinLoyaltyContact"
|
||||
import { SidebarEnums } from "../../../../types/sidebar"
|
||||
import { buttonSchema } from "../blocks/utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "../blocks/utils/linkConnection"
|
||||
|
||||
export const contactSchema = z.object({
|
||||
contact: z.array(
|
||||
@@ -49,9 +48,3 @@ export const joinLoyaltyContactSchema = z.object({
|
||||
})
|
||||
.merge(contactSchema),
|
||||
})
|
||||
|
||||
export const joinLoyaltyContactRefsSchema = z.object({
|
||||
join_loyalty_contact: z.object({
|
||||
button: linkConnectionRefsSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { SidebarEnums } from "../../../../types/sidebar"
|
||||
import { shortcutsBlockSchema, shortcutsRefsSchema } from "../blocks/shortcuts"
|
||||
import { shortcutsBlockSchema } from "../blocks/shortcuts"
|
||||
|
||||
export const quickLinksSchema = z
|
||||
.object({
|
||||
@@ -11,5 +11,3 @@ export const quickLinksSchema = z
|
||||
.default(SidebarEnums.blocks.QuickLinks),
|
||||
})
|
||||
.merge(shortcutsBlockSchema)
|
||||
|
||||
export const quickLinksRefschema = shortcutsRefsSchema
|
||||
|
||||
@@ -4,9 +4,7 @@ import { scriptedCardThemeEnum } from "../../../../enums/scriptedCard"
|
||||
import { SidebarEnums } from "../../../../types/sidebar"
|
||||
import {
|
||||
getInfoCardThemeFromDeprecatedCardTheme,
|
||||
infoCardBlockRefsSchema,
|
||||
infoCardBlockSchema,
|
||||
transformCardBlockRefs,
|
||||
transformInfoCardBlock,
|
||||
} from "../blocks/cardsGrid"
|
||||
|
||||
@@ -41,25 +39,3 @@ export const scriptedCardsSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
export const scriptedCardRefschema = z.object({
|
||||
scripted_card: z
|
||||
.object({
|
||||
scripted_cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: infoCardBlockRefsSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
let card = null
|
||||
if (data.scripted_cardConnection.edges.length) {
|
||||
card = transformCardBlockRefs(
|
||||
data.scripted_cardConnection.edges[0].node
|
||||
)
|
||||
}
|
||||
return card
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,11 +2,9 @@ import { z } from "zod"
|
||||
|
||||
import { SidebarEnums } from "../../../../types/sidebar"
|
||||
import {
|
||||
teaserCardBlockRefsSchema,
|
||||
teaserCardBlockSchema,
|
||||
transformTeaserCardBlock,
|
||||
} from "../blocks/cards/teaserCard"
|
||||
import { transformCardBlockRefs } from "../blocks/cardsGrid"
|
||||
|
||||
export const teaserCardsSchema = z.object({
|
||||
typename: z
|
||||
@@ -36,23 +34,3 @@ export const teaserCardsSchema = z.object({
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
export const teaserCardRefschema = z.object({
|
||||
teaser_card: z
|
||||
.object({
|
||||
teaser_cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: teaserCardBlockRefsSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
let card = null
|
||||
if (data.teaser_cardConnection.edges.length) {
|
||||
card = transformCardBlockRefs(data.teaser_cardConnection.edges[0].node)
|
||||
}
|
||||
return card
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -3,26 +3,11 @@ import { z } from "zod"
|
||||
import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/imageVault"
|
||||
|
||||
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
|
||||
import {
|
||||
cardGridRefsSchema,
|
||||
cardsGridSchema,
|
||||
} from "../schemas/blocks/cardsGrid"
|
||||
import {
|
||||
carouselCardsRefsSchema,
|
||||
carouselCardsSchema,
|
||||
} from "../schemas/blocks/carouselCards"
|
||||
import {
|
||||
fullWidthCampaignBlockRefsSchema,
|
||||
fullWidthCampaignBlockSchema,
|
||||
} from "../schemas/blocks/fullWidthCampaign"
|
||||
import {
|
||||
joinScandicFriendsBlockRefsSchema,
|
||||
joinScandicFriendsBlockSchema,
|
||||
} from "../schemas/blocks/joinScandicFriends"
|
||||
import {
|
||||
videoCardRefsSchema,
|
||||
videoCardSchema,
|
||||
} from "../schemas/blocks/videoCard"
|
||||
import { cardsGridSchema } from "../schemas/blocks/cardsGrid"
|
||||
import { carouselCardsSchema } from "../schemas/blocks/carouselCards"
|
||||
import { fullWidthCampaignBlockSchema } from "../schemas/blocks/fullWidthCampaign"
|
||||
import { joinScandicFriendsBlockSchema } from "../schemas/blocks/joinScandicFriends"
|
||||
import { videoCardSchema } from "../schemas/blocks/videoCard"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
import { StartPageEnum } from "./utils"
|
||||
|
||||
@@ -85,49 +70,3 @@ export const startPageSchema = z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
/** REFS */
|
||||
const startPageCardsRefs = z
|
||||
.object({
|
||||
__typename: z.literal(StartPageEnum.ContentStack.blocks.CardsGrid),
|
||||
})
|
||||
.merge(cardGridRefsSchema)
|
||||
|
||||
const startPageFullWidthCampaignRef = z
|
||||
.object({
|
||||
__typename: z.literal(StartPageEnum.ContentStack.blocks.FullWidthCampaign),
|
||||
})
|
||||
.merge(fullWidthCampaignBlockRefsSchema)
|
||||
|
||||
const startPageCarouselCardsRef = z
|
||||
.object({
|
||||
__typename: z.literal(StartPageEnum.ContentStack.blocks.CarouselCards),
|
||||
})
|
||||
.merge(carouselCardsRefsSchema)
|
||||
|
||||
const startPageJoinScandicFriendsRef = z
|
||||
.object({
|
||||
__typename: z.literal(StartPageEnum.ContentStack.blocks.JoinScandicFriends),
|
||||
})
|
||||
.merge(joinScandicFriendsBlockRefsSchema)
|
||||
|
||||
const startPageVideoCardRef = z
|
||||
.object({
|
||||
__typename: z.literal(StartPageEnum.ContentStack.blocks.VideoCard),
|
||||
})
|
||||
.merge(videoCardRefsSchema)
|
||||
|
||||
const startPageBlockRefsItem = z.discriminatedUnion("__typename", [
|
||||
startPageCardsRefs,
|
||||
startPageFullWidthCampaignRef,
|
||||
startPageCarouselCardsRef,
|
||||
startPageJoinScandicFriendsRef,
|
||||
startPageVideoCardRef,
|
||||
])
|
||||
|
||||
export const startPageRefsSchema = z.object({
|
||||
start_page: z.object({
|
||||
blocks: discriminatedUnionArray(startPageBlockRefsItem.options).nullable(),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,20 +2,11 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import { router } from "../../.."
|
||||
import { notFoundError } from "../../../errors"
|
||||
import {
|
||||
GetStartPage,
|
||||
GetStartPageRefs,
|
||||
} from "../../../graphql/Query/StartPage/StartPage.graphql"
|
||||
import { GetStartPage } from "../../../graphql/Query/StartPage/StartPage.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTagsFromAssetSystem,
|
||||
generateTagsFromSystem,
|
||||
} from "../../../utils/generateTag"
|
||||
import { startPageRefsSchema, startPageSchema } from "./output"
|
||||
import { getConnections } from "./utils"
|
||||
import { generateTag } from "../../../utils/generateTag"
|
||||
import { startPageSchema } from "./output"
|
||||
|
||||
import type { z } from "zod"
|
||||
|
||||
@@ -25,66 +16,19 @@ import type { blocksSchema } from "./output"
|
||||
export interface GetStartPageData extends z.input<typeof startPageSchema> {}
|
||||
export interface StartPage extends z.output<typeof startPageSchema> {}
|
||||
|
||||
export interface GetStartPageRefsSchema extends z.input<
|
||||
typeof startPageRefsSchema
|
||||
> {}
|
||||
|
||||
export type Block = z.output<typeof blocksSchema>
|
||||
|
||||
export const startPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const getStartPageRefsCounter = createCounter(
|
||||
"trpc.contentstack.startPage.get.refs"
|
||||
)
|
||||
const metricsGetStartPageRefs = getStartPageRefsCounter.init({ lang, uid })
|
||||
|
||||
metricsGetStartPageRefs.start()
|
||||
|
||||
const refsResponse = await request<GetStartPageRefsSchema>(
|
||||
GetStartPageRefs,
|
||||
{
|
||||
locale: lang,
|
||||
uid,
|
||||
},
|
||||
{
|
||||
key: generateRefsResponseTag(lang, uid),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
if (!refsResponse.data) {
|
||||
metricsGetStartPageRefs.noDataError()
|
||||
throw notFoundError({
|
||||
message: "StartPage refs returned no data",
|
||||
errorDetails: { lang, uid },
|
||||
})
|
||||
}
|
||||
|
||||
const validatedRefsData = startPageRefsSchema.safeParse(refsResponse.data)
|
||||
|
||||
if (!validatedRefsData.success) {
|
||||
metricsGetStartPageRefs.validationError(validatedRefsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetStartPageRefs.success()
|
||||
const cacheKey = generateTag(lang, uid)
|
||||
|
||||
const getStartPageCounter = createCounter("trpc.contentstack.startPage.get")
|
||||
const metricsGetStartPage = getStartPageCounter.init({ lang, uid })
|
||||
|
||||
metricsGetStartPage.start()
|
||||
|
||||
const { connections, assetConnections } = getConnections(
|
||||
validatedRefsData.data
|
||||
)
|
||||
|
||||
const tags = [
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTagsFromAssetSystem(assetConnections),
|
||||
generateTag(lang, validatedRefsData.data.start_page.system.uid),
|
||||
].flat()
|
||||
|
||||
const response = await request<GetStartPageData>(
|
||||
GetStartPage,
|
||||
{
|
||||
@@ -92,7 +36,7 @@ export const startPageQueryRouter = router({
|
||||
uid,
|
||||
},
|
||||
{
|
||||
key: tags,
|
||||
key: `${cacheKey}`,
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
import type { z } from "zod"
|
||||
|
||||
import type { AssetSystem, System } from "../schemas/system"
|
||||
import type { startPageRefsSchema } from "./output"
|
||||
|
||||
export namespace StartPageEnum {
|
||||
export namespace ContentStack {
|
||||
export const enum blocks {
|
||||
@@ -14,60 +9,3 @@ export namespace StartPageEnum {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface StartPageRefs extends z.output<typeof startPageRefsSchema> {}
|
||||
|
||||
export function getConnections({ start_page }: StartPageRefs) {
|
||||
const connections: System["system"][] = [start_page.system]
|
||||
const assetConnections: AssetSystem[] = []
|
||||
|
||||
if (start_page.blocks) {
|
||||
start_page.blocks.forEach((block) => {
|
||||
const typeName = block.__typename
|
||||
switch (typeName) {
|
||||
case StartPageEnum.ContentStack.blocks.FullWidthCampaign:
|
||||
block.full_width_campaign.full_width_campaignConnection.edges.forEach(
|
||||
({ node }) => {
|
||||
if (node.system) {
|
||||
connections.push(node.system)
|
||||
}
|
||||
}
|
||||
)
|
||||
break
|
||||
case StartPageEnum.ContentStack.blocks.CardsGrid:
|
||||
block.cards_grid.forEach((card) => {
|
||||
connections.push(card)
|
||||
})
|
||||
break
|
||||
case StartPageEnum.ContentStack.blocks.CarouselCards:
|
||||
block.carousel_cards.card_groups.forEach((group) => {
|
||||
group.cardConnection.edges.forEach((node) => {
|
||||
connections.push(node.node.system)
|
||||
})
|
||||
})
|
||||
break
|
||||
case StartPageEnum.ContentStack.blocks.JoinScandicFriends:
|
||||
if (block.join_scandic_friends.primary_button) {
|
||||
connections.push(block.join_scandic_friends.primary_button)
|
||||
}
|
||||
break
|
||||
case StartPageEnum.ContentStack.blocks.VideoCard: {
|
||||
if (block.video_card?.system) {
|
||||
connections.push(block.video_card.system)
|
||||
}
|
||||
if (block.video_card?.video.sourceConnection.edges[0]) {
|
||||
assetConnections.push(
|
||||
block.video_card.video.sourceConnection.edges[0].node
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
const _exhaustiveCheck: never = typeName
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return { connections, assetConnections }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user