feat(SW-66, SW-348): search functionality and ui
This commit is contained in:
@@ -1,197 +1,87 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
|
||||
|
||||
import {
|
||||
ContentEntries,
|
||||
DynamicContentComponents,
|
||||
} from "@/types/components/myPages/myPage/enums"
|
||||
import { Embeds } from "@/types/requests/embeds"
|
||||
import { PageLinkEnum } from "@/types/requests/pageLinks"
|
||||
import { Edges } from "@/types/requests/utils/edges"
|
||||
import { RTEDocument } from "@/types/rte/node"
|
||||
dynamicContentRefsSchema,
|
||||
dynamicContentSchema,
|
||||
} from "../schemas/blocks/dynamicContent"
|
||||
import {
|
||||
shortcutsRefsSchema,
|
||||
shortcutsSchema,
|
||||
} from "../schemas/blocks/shortcuts"
|
||||
import { textContentSchema } from "../schemas/blocks/textContent"
|
||||
import { page } from "../schemas/metadata"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
const accountPageShortcuts = z.object({
|
||||
__typename: z.literal(ContentEntries.AccountPageContentShortcuts),
|
||||
shortcuts: z.object({
|
||||
title: z.string().nullable(),
|
||||
preamble: z.string().nullable(),
|
||||
shortcuts: z.array(
|
||||
z.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
}),
|
||||
original_url: z.string().nullable().optional(),
|
||||
url: z.string(),
|
||||
title: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
text: z.string().nullable(),
|
||||
open_in_new_tab: z.boolean(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
import { AccountPageEnum } from "@/types/enums/accountPage"
|
||||
|
||||
const accountPageDynamicContent = z.object({
|
||||
__typename: z.literal(ContentEntries.AccountPageContentDynamicContent),
|
||||
dynamic_content: z.object({
|
||||
title: z.string().nullable(),
|
||||
preamble: z.string().nullable(),
|
||||
component: z.nativeEnum(DynamicContentComponents),
|
||||
link: z.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
}),
|
||||
url: z.string(),
|
||||
original_url: z.string().nullable().optional(),
|
||||
title: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
link_text: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
const accountPageDynamicContent = z
|
||||
.object({
|
||||
__typename: z.literal(AccountPageEnum.ContentStack.blocks.DynamicContent),
|
||||
})
|
||||
.merge(dynamicContentSchema)
|
||||
|
||||
const accountPageTextContent = z.object({
|
||||
__typename: z.literal(ContentEntries.AccountPageContentTextContent),
|
||||
text_content: z.object({
|
||||
content: z.object({
|
||||
json: z.any(),
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(z.any()),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
const accountPageShortcuts = z
|
||||
.object({
|
||||
__typename: z.literal(AccountPageEnum.ContentStack.blocks.ShortCuts),
|
||||
})
|
||||
.merge(shortcutsSchema)
|
||||
|
||||
type TextContentRaw = z.infer<typeof accountPageTextContent>
|
||||
const accountPageTextContent = z
|
||||
.object({
|
||||
__typename: z.literal(AccountPageEnum.ContentStack.blocks.TextContent),
|
||||
})
|
||||
.merge(textContentSchema)
|
||||
|
||||
type DynamicContentRaw = z.infer<typeof accountPageDynamicContent>
|
||||
|
||||
type ShortcutsRaw = z.infer<typeof accountPageShortcuts>
|
||||
|
||||
export type Shortcuts = Omit<ShortcutsRaw, "shortcuts"> & {
|
||||
shortcuts: Omit<ShortcutsRaw["shortcuts"], "shortcuts"> & {
|
||||
shortcuts: {
|
||||
text?: string
|
||||
openInNewTab: boolean
|
||||
url: string
|
||||
title: string
|
||||
}[]
|
||||
}
|
||||
}
|
||||
|
||||
export type RteTextContent = Omit<TextContentRaw, "text_content"> & {
|
||||
text_content: {
|
||||
content: {
|
||||
json: RTEDocument
|
||||
embedded_itemsConnection: Edges<Embeds>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type AccountPageContentItem =
|
||||
| DynamicContentRaw
|
||||
| Shortcuts
|
||||
| RteTextContent
|
||||
|
||||
const accountPageContentItem = z.discriminatedUnion("__typename", [
|
||||
accountPageShortcuts,
|
||||
export const blocksSchema = z.discriminatedUnion("__typename", [
|
||||
accountPageDynamicContent,
|
||||
accountPageShortcuts,
|
||||
accountPageTextContent,
|
||||
])
|
||||
|
||||
export const validateAccountPageSchema = z.object({
|
||||
export const accountPageSchema = z.object({
|
||||
account_page: z.object({
|
||||
content: discriminatedUnionArray(blocksSchema.options),
|
||||
heading: z.string().nullable(),
|
||||
url: z.string(),
|
||||
title: z.string(),
|
||||
content: z.array(accountPageContentItem),
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export type AccountPageDataRaw = z.infer<typeof validateAccountPageSchema>
|
||||
|
||||
type AccountPageRaw = AccountPageDataRaw["account_page"]
|
||||
|
||||
export type AccountPage = Omit<AccountPageRaw, "content"> & {
|
||||
content: AccountPageContentItem[]
|
||||
}
|
||||
|
||||
// Refs types
|
||||
const pageConnectionRefs = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
__typename: z.nativeEnum(PageLinkEnum),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
const accountPageShortcutsRefs = z.object({
|
||||
__typename: z.literal(ContentEntries.AccountPageContentShortcuts),
|
||||
shortcuts: z.object({
|
||||
shortcuts: z.array(
|
||||
url: z.string(),
|
||||
system: systemSchema.merge(
|
||||
z.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
const accountPageDynamicContentRefs = z.object({
|
||||
__typename: z.literal(ContentEntries.AccountPageContentDynamicContent),
|
||||
dynamic_content: z.object({
|
||||
link: z.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
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),
|
||||
}),
|
||||
accountPageDynamicContentRefs,
|
||||
accountPageShortcutsRefs,
|
||||
])
|
||||
|
||||
export const validateAccountPageRefsSchema = z.object({
|
||||
export const accountPageRefsSchema = z.object({
|
||||
account_page: z.object({
|
||||
content: z.array(accountPageContentItemRefs),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
content: discriminatedUnionArray(accountPageContentItemRefs.options),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
export type AccountPageRefsDataRaw = z.infer<
|
||||
typeof validateAccountPageRefsSchema
|
||||
>
|
||||
export const accountPageMetadataSchema = z.object({
|
||||
account_page: page,
|
||||
})
|
||||
|
||||
@@ -4,7 +4,8 @@ import { Lang } from "@/constants/languages"
|
||||
import {
|
||||
GetAccountPage,
|
||||
GetAccountPageRefs,
|
||||
} from "@/lib/graphql/Query/AccountPage.graphql"
|
||||
} from "@/lib/graphql/Query/AccountPage/AccountPage.graphql"
|
||||
import { GetMyPagesMetaData } from "@/lib/graphql/Query/AccountPage/MetaData.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { notFound } from "@/server/errors/trpc"
|
||||
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
@@ -12,27 +13,27 @@ import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTags,
|
||||
generateTagsFromSystem,
|
||||
} from "@/utils/generateTag"
|
||||
|
||||
import { removeEmptyObjects } from "../../utils"
|
||||
import { getMetaData, getResponse } from "../metadata/utils"
|
||||
import {
|
||||
type AccountPage,
|
||||
AccountPageDataRaw,
|
||||
AccountPageRefsDataRaw,
|
||||
validateAccountPageRefsSchema,
|
||||
validateAccountPageSchema,
|
||||
accountPageMetadataSchema,
|
||||
accountPageRefsSchema,
|
||||
accountPageSchema,
|
||||
} from "./output"
|
||||
import { getConnections } from "./utils"
|
||||
|
||||
import { ContentEntries } from "@/types/components/myPages/myPage/enums"
|
||||
import {
|
||||
TrackingChannelEnum,
|
||||
TrackingSDKPageData,
|
||||
type TrackingSDKPageData,
|
||||
} from "@/types/components/tracking"
|
||||
import { Embeds } from "@/types/requests/embeds"
|
||||
import { Edges } from "@/types/requests/utils/edges"
|
||||
import { RTEDocument } from "@/types/rte/node"
|
||||
import type {
|
||||
GetAccountpageMetadata,
|
||||
GetAccountPageRefsSchema,
|
||||
GetAccountPageSchema,
|
||||
} from "@/types/trpc/routers/contentstack/accountPage"
|
||||
|
||||
const meter = metrics.getMeter("trpc.accountPage")
|
||||
|
||||
@@ -64,7 +65,7 @@ export const accountPageQueryRouter = router({
|
||||
"contentstack.accountPage.refs start",
|
||||
JSON.stringify({ query: { lang, uid } })
|
||||
)
|
||||
const refsResponse = await request<AccountPageRefsDataRaw>(
|
||||
const refsResponse = await request<GetAccountPageRefsSchema>(
|
||||
GetAccountPageRefs,
|
||||
{
|
||||
locale: lang,
|
||||
@@ -96,10 +97,9 @@ export const accountPageQueryRouter = router({
|
||||
throw notFoundError
|
||||
}
|
||||
|
||||
const cleanedData = removeEmptyObjects(refsResponse.data)
|
||||
|
||||
const validatedAccountPageRefs =
|
||||
validateAccountPageRefsSchema.safeParse(cleanedData)
|
||||
const validatedAccountPageRefs = accountPageRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
if (!validatedAccountPageRefs.success) {
|
||||
getAccountPageRefsFailCounter.add(1, {
|
||||
lang,
|
||||
@@ -120,7 +120,7 @@ export const accountPageQueryRouter = router({
|
||||
const connections = getConnections(validatedAccountPageRefs.data)
|
||||
|
||||
const tags = [
|
||||
generateTags(lang, connections),
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, validatedAccountPageRefs.data.account_page.system.uid),
|
||||
].flat()
|
||||
getAccountPageRefsSuccessCounter.add(1, { lang, uid, tags })
|
||||
@@ -129,7 +129,7 @@ export const accountPageQueryRouter = router({
|
||||
"contentstack.accountPage start",
|
||||
JSON.stringify({ query: { lang, uid } })
|
||||
)
|
||||
const response = await request<AccountPageDataRaw>(
|
||||
const response = await request<GetAccountPageSchema>(
|
||||
GetAccountPage,
|
||||
{
|
||||
locale: lang,
|
||||
@@ -161,9 +161,7 @@ export const accountPageQueryRouter = router({
|
||||
throw notFoundError
|
||||
}
|
||||
|
||||
const validatedAccountPage = validateAccountPageSchema.safeParse(
|
||||
response.data
|
||||
)
|
||||
const validatedAccountPage = accountPageSchema.safeParse(response.data)
|
||||
|
||||
if (!validatedAccountPage.success) {
|
||||
getAccountPageFailCounter.add(1, {
|
||||
@@ -186,48 +184,6 @@ export const accountPageQueryRouter = router({
|
||||
"contentstack.accountPage success",
|
||||
JSON.stringify({ query: { lang, uid } })
|
||||
)
|
||||
// TODO: Make returned data nicer
|
||||
const content = validatedAccountPage.data.account_page.content.map(
|
||||
(block) => {
|
||||
switch (block.__typename) {
|
||||
case ContentEntries.AccountPageContentDynamicContent:
|
||||
return block
|
||||
case ContentEntries.AccountPageContentShortcuts:
|
||||
return {
|
||||
...block,
|
||||
shortcuts: {
|
||||
...block.shortcuts,
|
||||
shortcuts: block.shortcuts.shortcuts.map((shortcut) => ({
|
||||
text: shortcut.text,
|
||||
openInNewTab: shortcut.open_in_new_tab,
|
||||
...shortcut.linkConnection.edges[0].node,
|
||||
url:
|
||||
shortcut.linkConnection.edges[0].node.original_url ||
|
||||
`/${shortcut.linkConnection.edges[0].node.system.locale}${shortcut.linkConnection.edges[0].node.url}`,
|
||||
})),
|
||||
},
|
||||
}
|
||||
case ContentEntries.AccountPageContentTextContent:
|
||||
return {
|
||||
...block,
|
||||
text_content: {
|
||||
content: {
|
||||
json: block.text_content.content.json as RTEDocument,
|
||||
embedded_itemsConnection: block.text_content.content
|
||||
.embedded_itemsConnection as Edges<Embeds>,
|
||||
},
|
||||
},
|
||||
}
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const accountPage = {
|
||||
...validatedAccountPage.data.account_page,
|
||||
content,
|
||||
} as AccountPage
|
||||
|
||||
const parsedtitle = response.data.account_page.title
|
||||
.replaceAll(" ", "")
|
||||
@@ -243,8 +199,34 @@ export const accountPageQueryRouter = router({
|
||||
}
|
||||
|
||||
return {
|
||||
accountPage,
|
||||
accountPage: validatedAccountPage.data.account_page,
|
||||
tracking,
|
||||
}
|
||||
}),
|
||||
metadata: router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const variables = {
|
||||
locale: ctx.lang,
|
||||
uid: ctx.uid,
|
||||
}
|
||||
const response = await getResponse<GetAccountpageMetadata>(
|
||||
GetMyPagesMetaData,
|
||||
variables
|
||||
)
|
||||
|
||||
const validatedMetadata = accountPageMetadataSchema.safeParse(
|
||||
response.data
|
||||
)
|
||||
|
||||
if (!validatedMetadata.success) {
|
||||
console.error(
|
||||
`Failed to validate My Page MetaData Data - (uid: ${variables.uid})`
|
||||
)
|
||||
console.error(validatedMetadata.error)
|
||||
return null
|
||||
}
|
||||
|
||||
return getMetaData(validatedMetadata.data.account_page)
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,25 +1,22 @@
|
||||
import { AccountPageRefsDataRaw } from "./output"
|
||||
import { AccountPageEnum } from "@/types/enums/accountPage"
|
||||
import type { System } from "@/types/requests/system"
|
||||
import type { AccountPageRefs } from "@/types/trpc/routers/contentstack/accountPage"
|
||||
|
||||
import { ContentEntries } from "@/types/components/myPages/myPage/enums"
|
||||
import type { Edges } from "@/types/requests/utils/edges"
|
||||
import type { NodeRefs } from "@/types/requests/utils/refs"
|
||||
export function getConnections({ account_page }: AccountPageRefs) {
|
||||
const connections: System["system"][] = [account_page.system]
|
||||
|
||||
export function getConnections(refs: AccountPageRefsDataRaw) {
|
||||
const connections: Edges<NodeRefs>[] = []
|
||||
if (refs.account_page.content) {
|
||||
refs.account_page.content.forEach((item) => {
|
||||
switch (item.__typename) {
|
||||
case ContentEntries.AccountPageContentShortcuts: {
|
||||
item.shortcuts.shortcuts.forEach((shortcut) => {
|
||||
if (shortcut.linkConnection.edges.length) {
|
||||
connections.push(shortcut.linkConnection)
|
||||
}
|
||||
})
|
||||
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)
|
||||
}
|
||||
break
|
||||
}
|
||||
case ContentEntries.AccountPageContentDynamicContent: {
|
||||
if (item.dynamic_content.link.linkConnection.edges.length) {
|
||||
connections.push(item.dynamic_content.link.linkConnection)
|
||||
case AccountPageEnum.ContentStack.blocks.DynamicContent: {
|
||||
if (block.dynamic_content.link) {
|
||||
connections.push(block.dynamic_content.link)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Lang } from "@/constants/languages"
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import { imageVaultAssetTransformedSchema } from "../schemas/imageVault"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
import { Image } from "@/types/image"
|
||||
|
||||
@@ -68,74 +69,81 @@ export type ContactFields = {
|
||||
footnote: string | null
|
||||
}
|
||||
|
||||
export const validateCurrentHeaderConfigSchema = z.object({
|
||||
all_current_header: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
frontpage_link_text: z.string(),
|
||||
logoConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
description: z.string().optional().nullable(),
|
||||
dimension: z.object({
|
||||
height: z.number(),
|
||||
width: z.number(),
|
||||
export const validateCurrentHeaderConfigSchema = z
|
||||
.object({
|
||||
all_current_header: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
frontpage_link_text: z.string(),
|
||||
logoConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
description: z.string().optional().nullable(),
|
||||
dimension: z.object({
|
||||
height: z.number(),
|
||||
width: z.number(),
|
||||
}),
|
||||
metadata: z.any().nullable(),
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
}),
|
||||
title: z.string().optional().default(""),
|
||||
url: z.string().optional().default(""),
|
||||
}),
|
||||
metadata: z.any().nullable(),
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
}),
|
||||
title: z.string().nullable(),
|
||||
url: z.string().nullable(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
menu: z.object({
|
||||
links: z.array(
|
||||
z.object({
|
||||
href: z.string(),
|
||||
title: z.string(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
top_menu: z.object({
|
||||
links: z.array(
|
||||
z.object({
|
||||
link: z.object({
|
||||
})
|
||||
),
|
||||
}),
|
||||
menu: z.object({
|
||||
links: z.array(
|
||||
z.object({
|
||||
href: z.string(),
|
||||
title: z.string(),
|
||||
}),
|
||||
show_on_mobile: z.boolean(),
|
||||
sort_order_mobile: z.number(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
})
|
||||
),
|
||||
}),
|
||||
top_menu: z.object({
|
||||
links: z.array(
|
||||
z.object({
|
||||
link: z.object({
|
||||
href: z.string(),
|
||||
title: z.string(),
|
||||
}),
|
||||
show_on_mobile: z.boolean(),
|
||||
sort_order_mobile: z.number(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (!data.all_current_header.items.length) {
|
||||
return {
|
||||
header: null,
|
||||
}
|
||||
}
|
||||
const header = data.all_current_header.items[0]
|
||||
return {
|
||||
header: {
|
||||
frontpageLinkText: header.frontpage_link_text,
|
||||
logo: header.logoConnection.edges[0].node,
|
||||
menu: header.menu,
|
||||
topMenu: header.top_menu,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
export type CurrentHeaderDataRaw = z.infer<
|
||||
typeof validateCurrentHeaderConfigSchema
|
||||
>
|
||||
|
||||
export type CurrentHeaderData = Omit<
|
||||
CurrentHeaderDataRaw["all_current_header"]["items"][0],
|
||||
"logoConnection"
|
||||
> & {
|
||||
logo: Image
|
||||
}
|
||||
export interface GetCurrentHeaderData
|
||||
extends z.input<typeof validateCurrentHeaderConfigSchema> {}
|
||||
export type HeaderData = z.output<typeof validateCurrentHeaderConfigSchema>
|
||||
|
||||
const validateCurrentHeaderRefConfigSchema = z.object({
|
||||
all_current_header: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
@@ -257,10 +265,7 @@ const validateCurrentFooterRefConfigSchema = z.object({
|
||||
all_current_footer: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
@@ -387,10 +392,7 @@ const pageConnectionRefs = z.object({
|
||||
.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
)
|
||||
@@ -421,10 +423,7 @@ export const validateFooterRefConfigSchema = z.object({
|
||||
pageConnection: pageConnectionRefs,
|
||||
})
|
||||
),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
)
|
||||
.length(1),
|
||||
@@ -437,10 +436,7 @@ const linkConnectionNodeSchema = z
|
||||
.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
}),
|
||||
system: systemSchema,
|
||||
url: z.string(),
|
||||
title: z.string(),
|
||||
web: z.object({
|
||||
@@ -595,10 +591,7 @@ const linkConnectionRefs = z.object({
|
||||
.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
)
|
||||
@@ -656,10 +649,7 @@ export const getHeaderRefSchema = z.object({
|
||||
),
|
||||
})
|
||||
),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
)
|
||||
.length(1),
|
||||
|
||||
@@ -4,13 +4,19 @@ import { GetContactConfig } from "@/lib/graphql/Query/ContactConfig.graphql"
|
||||
import {
|
||||
GetCurrentFooter,
|
||||
GetCurrentFooterRef,
|
||||
} from "@/lib/graphql/Query/CurrentFooter.graphql"
|
||||
} from "@/lib/graphql/Query/Current/Footer.graphql"
|
||||
import {
|
||||
GetCurrentHeader,
|
||||
GetCurrentHeaderRef,
|
||||
} from "@/lib/graphql/Query/CurrentHeader.graphql"
|
||||
import { GetFooter, GetFooterRef } from "@/lib/graphql/Query/Footer.graphql"
|
||||
import { GetHeader, GetHeaderRef } from "@/lib/graphql/Query/Header.graphql"
|
||||
} from "@/lib/graphql/Query/Current/Header.graphql"
|
||||
import {
|
||||
GetFooter,
|
||||
GetFooterRef,
|
||||
} from "@/lib/graphql/Query/Footer.graphql"
|
||||
import {
|
||||
GetHeader,
|
||||
GetHeaderRef,
|
||||
} from "@/lib/graphql/Query/Header.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { notFound } from "@/server/errors/trpc"
|
||||
import { contentstackBaseProcedure, router } from "@/server/trpc"
|
||||
@@ -23,19 +29,18 @@ import {
|
||||
|
||||
import { langInput } from "./input"
|
||||
import {
|
||||
type GetCurrentHeaderData,
|
||||
type ContactConfigData,
|
||||
CurrentFooterDataRaw,
|
||||
CurrentFooterRefDataRaw,
|
||||
CurrentHeaderData,
|
||||
CurrentHeaderDataRaw,
|
||||
CurrentHeaderRefDataRaw,
|
||||
getHeaderRefSchema,
|
||||
getHeaderSchema,
|
||||
validateContactConfigSchema,
|
||||
validateCurrentFooterConfigSchema,
|
||||
validateCurrentHeaderConfigSchema,
|
||||
validateFooterConfigSchema,
|
||||
validateFooterRefConfigSchema,
|
||||
validateCurrentHeaderConfigSchema,
|
||||
} from "./output"
|
||||
import { getConnections, getFooterConnections } from "./utils"
|
||||
|
||||
@@ -357,7 +362,7 @@ export const baseQueryRouter = router({
|
||||
const currentHeaderUID =
|
||||
responseRef.data.all_current_header.items[0].system.uid
|
||||
// There's currently no error handling/validation for the responseRef, should it be added?
|
||||
const response = await request<CurrentHeaderDataRaw>(
|
||||
const response = await request<GetCurrentHeaderData>(
|
||||
GetCurrentHeader,
|
||||
{ locale: input.lang },
|
||||
{
|
||||
@@ -415,14 +420,8 @@ export const baseQueryRouter = router({
|
||||
query: { lang: input.lang },
|
||||
})
|
||||
)
|
||||
const logo =
|
||||
validatedHeaderConfig.data.all_current_header.items[0].logoConnection
|
||||
.edges?.[0]?.node
|
||||
|
||||
return {
|
||||
...validatedHeaderConfig.data.all_current_header.items[0],
|
||||
logo,
|
||||
} as CurrentHeaderData
|
||||
return validatedHeaderConfig.data
|
||||
}),
|
||||
currentFooter: contentstackBaseProcedure
|
||||
.input(langInput)
|
||||
|
||||
@@ -21,73 +21,74 @@ import { affix as bookingwidgetAffix } from "./utils"
|
||||
import { ContentTypeEnum } from "@/types/requests/contentType"
|
||||
|
||||
export const bookingwidgetQueryRouter = router({
|
||||
getToggle: contentstackBaseProcedure.query(async ({ ctx }) => {
|
||||
const failedResponse = { hideBookingWidget: false }
|
||||
const { contentType, uid, lang } = ctx
|
||||
toggle: router({
|
||||
get: contentstackBaseProcedure.query(async ({ ctx }) => {
|
||||
const failedResponse = { hideBookingWidget: false }
|
||||
const { contentType, uid, lang } = ctx
|
||||
|
||||
// This condition is to handle 404 page case
|
||||
if (!contentType || !uid) {
|
||||
console.log("No proper params defined: ", contentType, uid)
|
||||
return failedResponse
|
||||
}
|
||||
let GetPageSettings = ""
|
||||
const contentTypeCMS = <ValueOf<typeof ContentTypeEnum>>(
|
||||
contentType.replaceAll("-", "_")
|
||||
)
|
||||
|
||||
switch (contentTypeCMS) {
|
||||
case ContentTypeEnum.accountPage:
|
||||
GetPageSettings = GetAccountPageSettings
|
||||
break
|
||||
case ContentTypeEnum.loyaltyPage:
|
||||
GetPageSettings = GetLoyaltyPageSettings
|
||||
break
|
||||
case ContentTypeEnum.contentPage:
|
||||
GetPageSettings = GetContentPageSettings
|
||||
break
|
||||
case ContentTypeEnum.hotelPage:
|
||||
GetPageSettings = GetHotelPageSettings
|
||||
break
|
||||
case ContentTypeEnum.currentBlocksPage:
|
||||
GetPageSettings = GetCurrentBlocksPageSettings
|
||||
break
|
||||
}
|
||||
|
||||
if (!GetPageSettings) {
|
||||
console.error("No proper Content type defined: ", contentType)
|
||||
return failedResponse
|
||||
}
|
||||
|
||||
const response = await request<ValidateBookingWidgetToggleType>(
|
||||
GetPageSettings,
|
||||
{
|
||||
uid: uid,
|
||||
locale: lang,
|
||||
},
|
||||
{
|
||||
next: {
|
||||
tags: [generateTag(lang, uid, bookingwidgetAffix)],
|
||||
},
|
||||
// This condition is to handle 404 page case
|
||||
if (!contentType || !uid) {
|
||||
console.log("No proper params defined: ", contentType, uid)
|
||||
return failedResponse
|
||||
}
|
||||
)
|
||||
|
||||
const bookingWidgetToggleData = validateBookingWidgetToggleSchema.safeParse(
|
||||
response.data
|
||||
)
|
||||
if (!bookingWidgetToggleData.success) {
|
||||
console.error(
|
||||
"Flag hide_booking_widget fetch error: ",
|
||||
bookingWidgetToggleData.error
|
||||
let GetPageSettings = ""
|
||||
const contentTypeCMS = <ValueOf<typeof ContentTypeEnum>>(
|
||||
contentType.replaceAll("-", "_")
|
||||
)
|
||||
return failedResponse
|
||||
}
|
||||
|
||||
const hideBookingWidget =
|
||||
bookingWidgetToggleData.data[contentTypeCMS]?.page_settings
|
||||
?.hide_booking_widget
|
||||
switch (contentTypeCMS) {
|
||||
case ContentTypeEnum.accountPage:
|
||||
GetPageSettings = GetAccountPageSettings
|
||||
break
|
||||
case ContentTypeEnum.loyaltyPage:
|
||||
GetPageSettings = GetLoyaltyPageSettings
|
||||
break
|
||||
case ContentTypeEnum.contentPage:
|
||||
GetPageSettings = GetContentPageSettings
|
||||
break
|
||||
case ContentTypeEnum.hotelPage:
|
||||
GetPageSettings = GetHotelPageSettings
|
||||
break
|
||||
case ContentTypeEnum.currentBlocksPage:
|
||||
GetPageSettings = GetCurrentBlocksPageSettings
|
||||
break
|
||||
}
|
||||
|
||||
return {
|
||||
hideBookingWidget,
|
||||
}
|
||||
if (!GetPageSettings) {
|
||||
console.error("No proper Content type defined: ", contentType)
|
||||
return failedResponse
|
||||
}
|
||||
|
||||
const response = await request<ValidateBookingWidgetToggleType>(
|
||||
GetPageSettings,
|
||||
{
|
||||
uid: uid,
|
||||
locale: lang,
|
||||
},
|
||||
{
|
||||
next: {
|
||||
tags: [generateTag(lang, uid, bookingwidgetAffix)],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const bookingWidgetToggleData =
|
||||
validateBookingWidgetToggleSchema.safeParse(response.data)
|
||||
if (!bookingWidgetToggleData.success) {
|
||||
console.error(
|
||||
"Flag hide_booking_widget fetch error: ",
|
||||
bookingWidgetToggleData.error
|
||||
)
|
||||
return failedResponse
|
||||
}
|
||||
|
||||
const hideBookingWidget =
|
||||
!!bookingWidgetToggleData.data[contentTypeCMS]?.page_settings
|
||||
?.hide_booking_widget
|
||||
|
||||
return {
|
||||
hideBookingWidget,
|
||||
}
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
export const getBreadcrumbsSchema = z.array(
|
||||
z.object({
|
||||
@@ -10,42 +10,32 @@ export const getBreadcrumbsSchema = z.array(
|
||||
})
|
||||
)
|
||||
|
||||
const breadcrumbsRefsItems = z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
web: z
|
||||
const breadcrumbsRefs = z.object({
|
||||
web: z
|
||||
.object({
|
||||
breadcrumbs: z
|
||||
.object({
|
||||
breadcrumbs: z
|
||||
.object({
|
||||
title: z.string(),
|
||||
parentsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.optional(),
|
||||
title: z.string(),
|
||||
parentsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.optional(),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
.optional(),
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export type BreadcrumbsRefsItems = z.infer<typeof breadcrumbsRefsItems>
|
||||
export type BreadcrumbsRefs = z.infer<typeof breadcrumbsRefs>
|
||||
|
||||
export const validateMyPagesBreadcrumbsRefsContentstackSchema = z.object({
|
||||
all_account_page: breadcrumbsRefsItems,
|
||||
account_page: breadcrumbsRefs,
|
||||
})
|
||||
|
||||
export type GetMyPagesBreadcrumbsRefsData = z.infer<
|
||||
@@ -53,7 +43,7 @@ export type GetMyPagesBreadcrumbsRefsData = z.infer<
|
||||
>
|
||||
|
||||
export const validateLoyaltyPageBreadcrumbsRefsContentstackSchema = z.object({
|
||||
all_loyalty_page: breadcrumbsRefsItems,
|
||||
loyalty_page: breadcrumbsRefs,
|
||||
})
|
||||
|
||||
export type GetLoyaltyPageBreadcrumbsRefsData = z.infer<
|
||||
@@ -61,7 +51,7 @@ export type GetLoyaltyPageBreadcrumbsRefsData = z.infer<
|
||||
>
|
||||
|
||||
export const validateContentPageBreadcrumbsRefsContentstackSchema = z.object({
|
||||
all_content_page: breadcrumbsRefsItems,
|
||||
content_page: breadcrumbsRefs,
|
||||
})
|
||||
|
||||
export type GetContentPageBreadcrumbsRefsData = z.infer<
|
||||
@@ -81,10 +71,7 @@ const page = z.object({
|
||||
title: z.string(),
|
||||
}),
|
||||
}),
|
||||
system: z.object({
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
@@ -92,19 +79,13 @@ const page = z.object({
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export type Page = z.infer<typeof page>
|
||||
|
||||
const breadcrumbsItems = z.object({
|
||||
items: z.array(page),
|
||||
})
|
||||
|
||||
export const validateMyPagesBreadcrumbsContentstackSchema = z.object({
|
||||
all_account_page: breadcrumbsItems,
|
||||
account_page: page,
|
||||
})
|
||||
|
||||
export type GetMyPagesBreadcrumbsData = z.infer<
|
||||
@@ -112,7 +93,7 @@ export type GetMyPagesBreadcrumbsData = z.infer<
|
||||
>
|
||||
|
||||
export const validateLoyaltyPageBreadcrumbsContentstackSchema = z.object({
|
||||
all_loyalty_page: breadcrumbsItems,
|
||||
loyalty_page: page,
|
||||
})
|
||||
|
||||
export type GetLoyaltyPageBreadcrumbsData = z.infer<
|
||||
@@ -120,7 +101,7 @@ export type GetLoyaltyPageBreadcrumbsData = z.infer<
|
||||
>
|
||||
|
||||
export const validateContentPageBreadcrumbsContentstackSchema = z.object({
|
||||
all_content_page: breadcrumbsItems,
|
||||
content_page: page,
|
||||
})
|
||||
|
||||
export type GetContentPageBreadcrumbsData = z.infer<
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import {
|
||||
GetContentPageBreadcrumbs,
|
||||
GetContentPageBreadcrumbsRefs,
|
||||
} from "@/lib/graphql/Query/BreadcrumbsContentPage.graphql"
|
||||
import {
|
||||
GetLoyaltyPageBreadcrumbs,
|
||||
GetLoyaltyPageBreadcrumbsRefs,
|
||||
} from "@/lib/graphql/Query/BreadcrumbsLoyaltyPage.graphql"
|
||||
import {
|
||||
GetMyPagesBreadcrumbs,
|
||||
GetMyPagesBreadcrumbsRefs,
|
||||
} from "@/lib/graphql/Query/BreadcrumbsMyPages.graphql"
|
||||
} from "@/lib/graphql/Query/Breadcrumbs/AccountPage.graphql"
|
||||
import {
|
||||
GetContentPageBreadcrumbs,
|
||||
GetContentPageBreadcrumbsRefs,
|
||||
} from "@/lib/graphql/Query/Breadcrumbs/ContentPage.graphql"
|
||||
import {
|
||||
GetLoyaltyPageBreadcrumbs,
|
||||
GetLoyaltyPageBreadcrumbsRefs,
|
||||
} from "@/lib/graphql/Query/Breadcrumbs/LoyaltyPage.graphql"
|
||||
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
|
||||
import {
|
||||
@@ -49,13 +49,13 @@ async function getLoyaltyPageBreadcrumbs(variables: Variables) {
|
||||
|
||||
if (!validatedRefsData.success) {
|
||||
console.error(
|
||||
`Failed to validate Loyaltypage Breadcrumbs Refs - (url: ${variables.url})`
|
||||
`Failed to validate Loyaltypage Breadcrumbs Refs - (uid: ${variables.uid})`
|
||||
)
|
||||
console.error(validatedRefsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
const tags = getTags(validatedRefsData.data.all_loyalty_page, variables)
|
||||
const tags = getTags(validatedRefsData.data.loyalty_page, variables)
|
||||
|
||||
const response = await getResponse<GetLoyaltyPageBreadcrumbsData>(
|
||||
GetLoyaltyPageBreadcrumbs,
|
||||
@@ -63,7 +63,7 @@ async function getLoyaltyPageBreadcrumbs(variables: Variables) {
|
||||
tags
|
||||
)
|
||||
|
||||
if (!response.data.all_loyalty_page.items[0].web?.breadcrumbs?.title) {
|
||||
if (!response.data.loyalty_page.web?.breadcrumbs?.title) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -72,14 +72,14 @@ async function getLoyaltyPageBreadcrumbs(variables: Variables) {
|
||||
|
||||
if (!validatedBreadcrumbsData.success) {
|
||||
console.error(
|
||||
`Failed to validate Loyaltypage Breadcrumbs Data - (url: ${variables.url})`
|
||||
`Failed to validate Loyaltypage Breadcrumbs Data - (uid: ${variables.uid})`
|
||||
)
|
||||
console.error(validatedBreadcrumbsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
return getBreadcrumbs(
|
||||
validatedBreadcrumbsData.data.all_loyalty_page.items[0],
|
||||
validatedBreadcrumbsData.data.loyalty_page,
|
||||
variables.locale
|
||||
)
|
||||
}
|
||||
@@ -97,13 +97,13 @@ async function getContentPageBreadcrumbs(variables: Variables) {
|
||||
|
||||
if (!validatedRefsData.success) {
|
||||
console.error(
|
||||
`Failed to validate Contentpage Breadcrumbs Refs - (url: ${variables.url})`
|
||||
`Failed to validate Contentpage Breadcrumbs Refs - (uid: ${variables.uid})`
|
||||
)
|
||||
console.error(validatedRefsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
const tags = getTags(validatedRefsData.data.all_content_page, variables)
|
||||
const tags = getTags(validatedRefsData.data.content_page, variables)
|
||||
|
||||
const response = await getResponse<GetContentPageBreadcrumbsData>(
|
||||
GetContentPageBreadcrumbs,
|
||||
@@ -111,7 +111,7 @@ async function getContentPageBreadcrumbs(variables: Variables) {
|
||||
tags
|
||||
)
|
||||
|
||||
if (!response.data.all_content_page.items[0].web?.breadcrumbs?.title) {
|
||||
if (!response.data.content_page.web?.breadcrumbs?.title) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -120,14 +120,14 @@ async function getContentPageBreadcrumbs(variables: Variables) {
|
||||
|
||||
if (!validatedBreadcrumbsData.success) {
|
||||
console.error(
|
||||
`Failed to validate Contentpage Breadcrumbs Data - (url: ${variables.url})`
|
||||
`Failed to validate Contentpage Breadcrumbs Data - (uid: ${variables.uid})`
|
||||
)
|
||||
console.error(validatedBreadcrumbsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
return getBreadcrumbs(
|
||||
validatedBreadcrumbsData.data.all_content_page.items[0],
|
||||
validatedBreadcrumbsData.data.content_page,
|
||||
variables.locale
|
||||
)
|
||||
}
|
||||
@@ -144,13 +144,13 @@ async function getMyPagesBreadcrumbs(variables: Variables) {
|
||||
)
|
||||
if (!validatedRefsData.success) {
|
||||
console.error(
|
||||
`Failed to validate My Page Breadcrumbs Refs - (url: ${variables.url})`
|
||||
`Failed to validate My Page Breadcrumbs Refs - (uid: ${variables.uid})`
|
||||
)
|
||||
console.error(validatedRefsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
const tags = getTags(validatedRefsData.data.all_account_page, variables)
|
||||
const tags = getTags(validatedRefsData.data.account_page, variables)
|
||||
|
||||
const response = await getResponse<GetMyPagesBreadcrumbsData>(
|
||||
GetMyPagesBreadcrumbs,
|
||||
@@ -158,7 +158,7 @@ async function getMyPagesBreadcrumbs(variables: Variables) {
|
||||
tags
|
||||
)
|
||||
|
||||
if (!response.data.all_account_page.items[0].web?.breadcrumbs?.title) {
|
||||
if (!response.data.account_page.web?.breadcrumbs?.title) {
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -167,14 +167,14 @@ async function getMyPagesBreadcrumbs(variables: Variables) {
|
||||
|
||||
if (!validatedBreadcrumbsData.success) {
|
||||
console.error(
|
||||
`Failed to validate My Page Breadcrumbs Data - (url: ${variables.url})`
|
||||
`Failed to validate My Page Breadcrumbs Data - (uid: ${variables.uid})`
|
||||
)
|
||||
console.error(validatedBreadcrumbsData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
return getBreadcrumbs(
|
||||
validatedBreadcrumbsData.data.all_account_page.items[0],
|
||||
validatedBreadcrumbsData.data.account_page,
|
||||
variables.locale
|
||||
)
|
||||
}
|
||||
@@ -183,7 +183,7 @@ export const breadcrumbsQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const variables = {
|
||||
locale: ctx.lang,
|
||||
url: ctx.pathname,
|
||||
uid: ctx.uid,
|
||||
}
|
||||
|
||||
switch (ctx.contentType) {
|
||||
|
||||
@@ -9,19 +9,18 @@ import {
|
||||
} from "@/utils/generateTag"
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import { type BreadcrumbsRefsItems, getBreadcrumbsSchema, Page } from "./output"
|
||||
import { type BreadcrumbsRefs, getBreadcrumbsSchema, Page } from "./output"
|
||||
|
||||
import type { Edges } from "@/types/requests/utils/edges"
|
||||
import type { NodeRefs } from "@/types/requests/utils/refs"
|
||||
|
||||
export function getConnections(refs: BreadcrumbsRefsItems) {
|
||||
export function getConnections(refs: BreadcrumbsRefs) {
|
||||
const connections: Edges<NodeRefs>[] = []
|
||||
|
||||
refs.items.forEach((ref) => {
|
||||
if (ref.web?.breadcrumbs) {
|
||||
connections.push(ref.web.breadcrumbs.parentsConnection)
|
||||
}
|
||||
})
|
||||
if (refs.web?.breadcrumbs) {
|
||||
connections.push(refs.web.breadcrumbs.parentsConnection)
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
@@ -63,14 +62,14 @@ export const homeBreadcrumbs = {
|
||||
|
||||
export type Variables = {
|
||||
locale: Lang
|
||||
url: string
|
||||
uid: string
|
||||
}
|
||||
|
||||
export async function getRefsResponse<T>(query: string, variables: Variables) {
|
||||
const refsResponse = await request<T>(query, variables, {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: [generateRefsResponseTag(variables.locale, variables.url, affix)],
|
||||
tags: [generateRefsResponseTag(variables.locale, variables.uid, affix)],
|
||||
},
|
||||
})
|
||||
if (!refsResponse.data) {
|
||||
@@ -80,10 +79,10 @@ export async function getRefsResponse<T>(query: string, variables: Variables) {
|
||||
return refsResponse
|
||||
}
|
||||
|
||||
export function getTags(page: BreadcrumbsRefsItems, variables: Variables) {
|
||||
export function getTags(page: BreadcrumbsRefs, variables: Variables) {
|
||||
const connections = getConnections(page)
|
||||
const tags = generateTags(variables.locale, connections)
|
||||
tags.push(generateTag(variables.locale, page.items[0].system.uid, affix))
|
||||
tags.push(generateTag(variables.locale, page.system.uid, affix))
|
||||
return tags
|
||||
}
|
||||
|
||||
|
||||
@@ -1,386 +1,187 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
import { imageVaultAssetSchema } from "../schemas/imageVault"
|
||||
import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
|
||||
|
||||
import {
|
||||
CardsGridEnum,
|
||||
ContentBlocksTypenameEnum,
|
||||
DynamicContentComponentEnum,
|
||||
JoinLoyaltyContactTypenameEnum,
|
||||
SidebarDynamicComponentEnum,
|
||||
SidebarTypenameEnum,
|
||||
} from "@/types/components/content/enums"
|
||||
import { PageLinkEnum } from "@/types/requests/pageLinks"
|
||||
import { RTEEmbedsEnum } from "@/types/requests/rte"
|
||||
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 { tempImageVaultAssetSchema } from "../schemas/imageVault"
|
||||
import {
|
||||
contentRefsSchema as sidebarContentRefsSchema,
|
||||
contentSchema as sidebarContentSchema,
|
||||
} from "../schemas/sidebar/content"
|
||||
import { dynamicContentSchema as sidebarDynamicContentSchema } from "../schemas/sidebar/dynamicContent"
|
||||
import {
|
||||
joinLoyaltyContactRefsSchema,
|
||||
joinLoyaltyContactSchema,
|
||||
} from "../schemas/sidebar/joinLoyaltyContact"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
import { ContentPageEnum } from "@/types/enums/contentPage"
|
||||
import { textColsRefsSchema, textColsSchema } from "../schemas/blocks/textCols"
|
||||
|
||||
// Block schemas
|
||||
export const contentPageBlockTextContent = z.object({
|
||||
__typename: z.literal(ContentBlocksTypenameEnum.ContentPageBlocksContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(z.any()),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
json: z.any(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
export const contentPageCards = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.CardsGrid),
|
||||
})
|
||||
.merge(cardsGridSchema)
|
||||
|
||||
export const contentPageShortcuts = z.object({
|
||||
__typename: z.literal(ContentBlocksTypenameEnum.ContentPageBlocksShortcuts),
|
||||
shortcuts: z.object({
|
||||
title: z.string().nullable(),
|
||||
preamble: z.string().nullable(),
|
||||
shortcuts: z.array(
|
||||
z.object({
|
||||
text: z.string().optional(),
|
||||
openInNewTab: z.boolean(),
|
||||
url: z.string(),
|
||||
title: z.string(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
export const contentPageContent = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Content),
|
||||
})
|
||||
.merge(blockContentSchema)
|
||||
|
||||
export const contentPageDynamicContent = z.object({
|
||||
__typename: z.literal(
|
||||
ContentBlocksTypenameEnum.ContentPageBlocksDynamicContent
|
||||
),
|
||||
dynamic_content: z.object({
|
||||
title: z.string().nullable(),
|
||||
subtitle: z.string().nullable(),
|
||||
component: z.nativeEnum(DynamicContentComponentEnum),
|
||||
link: z
|
||||
.object({
|
||||
text: z.string(),
|
||||
href: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
})
|
||||
export const contentPageDynamicContent = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.DynamicContent),
|
||||
})
|
||||
.merge(blockDynamicContentSchema)
|
||||
|
||||
export const cardBlock = z.object({
|
||||
__typename: z.literal(CardsGridEnum.Card),
|
||||
isContentCard: z.boolean(),
|
||||
heading: z.string().nullable(),
|
||||
body_text: z.string().nullable(),
|
||||
background_image: z.any(),
|
||||
scripted_top_title: z.string().nullable(),
|
||||
primaryButton: z
|
||||
.object({
|
||||
openInNewTab: z.boolean(),
|
||||
title: z.string(),
|
||||
href: z.string(),
|
||||
isExternal: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
secondaryButton: z
|
||||
.object({
|
||||
openInNewTab: z.boolean(),
|
||||
title: z.string(),
|
||||
href: z.string(),
|
||||
isExternal: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
sidePeekButton: z
|
||||
.object({
|
||||
title: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
system: z.object({
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
export const loyaltyCardBlock = z.object({
|
||||
__typename: z.literal(CardsGridEnum.LoyaltyCard),
|
||||
heading: z.string().nullable(),
|
||||
body_text: z.string().nullable(),
|
||||
image: z.any(),
|
||||
link: z
|
||||
.object({
|
||||
openInNewTab: z.boolean(),
|
||||
title: z.string(),
|
||||
href: z.string(),
|
||||
isExternal: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
system: z.object({
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
const contentPageCardsItems = z.discriminatedUnion("__typename", [
|
||||
loyaltyCardBlock,
|
||||
cardBlock,
|
||||
])
|
||||
|
||||
export const contentPageCards = z.object({
|
||||
__typename: z.literal(ContentBlocksTypenameEnum.ContentPageBlocksCardsGrid),
|
||||
cards_grid: z.object({
|
||||
title: z.string().nullable(),
|
||||
preamble: z.string().nullable(),
|
||||
layout: z.enum(["twoColumnGrid", "threeColumnGrid", "twoPlusOne"]),
|
||||
theme: z.enum(["one", "two", "three"]).nullable(),
|
||||
cards: z.array(contentPageCardsItems),
|
||||
}),
|
||||
})
|
||||
export const contentPageShortcuts = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Shortcuts),
|
||||
})
|
||||
.merge(shortcutsSchema)
|
||||
|
||||
export const contentPageTextCols = z.object({
|
||||
__typename: z.literal(ContentBlocksTypenameEnum.ContentPageBlocksTextCols),
|
||||
text_cols: z.object({
|
||||
columns: z.array(
|
||||
z.object({
|
||||
title: z.string(),
|
||||
text: z.object({
|
||||
json: z.any(),
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(z.any()),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
const contentPageBlockItem = z.discriminatedUnion("__typename", [
|
||||
contentPageBlockTextContent,
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.TextCols),
|
||||
}).merge(textColsSchema)
|
||||
|
||||
export const blocksSchema = z.discriminatedUnion("__typename", [
|
||||
contentPageCards,
|
||||
contentPageContent,
|
||||
contentPageDynamicContent,
|
||||
contentPageShortcuts,
|
||||
contentPageTextCols,
|
||||
])
|
||||
|
||||
export const contentPageSidebarTextContent = z.object({
|
||||
__typename: z.literal(SidebarTypenameEnum.ContentPageSidebarContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(z.any()),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
json: z.any(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
export const contentPageSidebarContent = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.sidebar.Content),
|
||||
})
|
||||
.merge(sidebarContentSchema)
|
||||
|
||||
export const contentPageJoinLoyaltyContact = z.object({
|
||||
__typename: z.literal(
|
||||
SidebarTypenameEnum.ContentPageSidebarJoinLoyaltyContact
|
||||
),
|
||||
join_loyalty_contact: z.object({
|
||||
title: z.string().nullable(),
|
||||
preamble: z.string().nullable(),
|
||||
button: z
|
||||
.object({
|
||||
openInNewTab: z.boolean(),
|
||||
title: z.string(),
|
||||
href: z.string(),
|
||||
isExternal: z.boolean(),
|
||||
})
|
||||
.nullable(),
|
||||
contact: z.array(
|
||||
z.object({
|
||||
__typename: z.literal(
|
||||
JoinLoyaltyContactTypenameEnum.ContentPageSidebarJoinLoyaltyContactBlockContactContact
|
||||
),
|
||||
contact: z.object({
|
||||
display_text: z.string().nullable(),
|
||||
contact_field: z.string(),
|
||||
footnote: z.string().nullable(),
|
||||
}),
|
||||
})
|
||||
export const contentPageSidebarDynamicContent = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.sidebar.DynamicContent),
|
||||
})
|
||||
.merge(sidebarDynamicContentSchema)
|
||||
|
||||
export const contentPageJoinLoyaltyContact = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
ContentPageEnum.ContentStack.sidebar.JoinLoyaltyContact
|
||||
),
|
||||
}),
|
||||
})
|
||||
})
|
||||
.merge(joinLoyaltyContactSchema)
|
||||
|
||||
export const contentPageSidebarDynamicContent = z.object({
|
||||
__typename: z.literal(SidebarTypenameEnum.ContentPageSidebarDynamicContent),
|
||||
dynamic_content: z.object({
|
||||
component: z.nativeEnum(SidebarDynamicComponentEnum),
|
||||
}),
|
||||
})
|
||||
|
||||
const contentPageSidebarItem = z.discriminatedUnion("__typename", [
|
||||
contentPageSidebarTextContent,
|
||||
export const sidebarSchema = z.discriminatedUnion("__typename", [
|
||||
contentPageSidebarContent,
|
||||
contentPageSidebarDynamicContent,
|
||||
contentPageJoinLoyaltyContact,
|
||||
])
|
||||
|
||||
// Content Page Schema and types
|
||||
export const validateContentPageSchema = z.object({
|
||||
export const contentPageSchema = z.object({
|
||||
content_page: z.object({
|
||||
hero_image: tempImageVaultAssetSchema,
|
||||
blocks: discriminatedUnionArray(blocksSchema.options).nullable(),
|
||||
sidebar: discriminatedUnionArray(sidebarSchema.options).nullable(),
|
||||
title: z.string(),
|
||||
header: z.object({
|
||||
heading: z.string(),
|
||||
preamble: z.string(),
|
||||
}),
|
||||
hero_image: imageVaultAssetSchema.nullable().optional(),
|
||||
blocks: z.array(contentPageBlockItem).nullable(),
|
||||
sidebar: z.array(contentPageSidebarItem).nullable(),
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const pageConnectionRefs = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
__typename: z.nativeEnum(PageLinkEnum),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
const rteConnectionRefs = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
__typename: z.nativeEnum(RTEEmbedsEnum),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
const cardBlockRefs = z.object({
|
||||
__typename: z.literal(CardsGridEnum.Card),
|
||||
primary_button: z
|
||||
.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
})
|
||||
.nullable(),
|
||||
secondary_button: z
|
||||
.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
})
|
||||
.nullable(),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyCardBlockRefs = z.object({
|
||||
__typename: z.literal(CardsGridEnum.LoyaltyCard),
|
||||
link: z
|
||||
.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
})
|
||||
.nullable(),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
const cardGridCardsRef = z.discriminatedUnion("__typename", [
|
||||
loyaltyCardBlockRefs,
|
||||
cardBlockRefs,
|
||||
])
|
||||
|
||||
const contentPageBlockTextContentRefs = z.object({
|
||||
__typename: z.literal(ContentBlocksTypenameEnum.ContentPageBlocksContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: rteConnectionRefs,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const contentPageCardsRefs = z.object({
|
||||
__typename: z.literal(ContentBlocksTypenameEnum.ContentPageBlocksCardsGrid),
|
||||
cards_grid: z.object({
|
||||
cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: cardGridCardsRef,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const contentPageShortcutsRefs = z.object({
|
||||
__typename: z.literal(ContentBlocksTypenameEnum.ContentPageBlocksShortcuts),
|
||||
shortcuts: z.object({
|
||||
shortcuts: z.array(
|
||||
system: systemSchema.merge(
|
||||
z.object({
|
||||
linkConnection: rteConnectionRefs,
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
const contentPageDynamicContentRefs = z.object({
|
||||
__typename: z.literal(
|
||||
ContentBlocksTypenameEnum.ContentPageBlocksDynamicContent
|
||||
),
|
||||
dynamic_content: z.object({
|
||||
link: z.object({
|
||||
pageConnection: pageConnectionRefs,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
/** 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 contentPageBlockRefsItem = z.discriminatedUnion("__typename", [
|
||||
contentPageBlockTextContentRefs,
|
||||
contentPageBlockContentRefs,
|
||||
contentPageShortcutsRefs,
|
||||
contentPageCardsRefs,
|
||||
contentPageDynamicContentRefs,
|
||||
contentPageTextColsRefs,
|
||||
])
|
||||
|
||||
const contentPageSidebarTextContentRef = z.object({
|
||||
__typename: z.literal(SidebarTypenameEnum.ContentPageSidebarContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: rteConnectionRefs,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
const contentPageSidebarContentRef = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.sidebar.Content),
|
||||
})
|
||||
.merge(sidebarContentRefsSchema)
|
||||
|
||||
const contentPageSidebarJoinLoyaltyContactRef = z.object({
|
||||
__typename: z.literal(
|
||||
SidebarTypenameEnum.ContentPageSidebarJoinLoyaltyContact
|
||||
),
|
||||
join_loyalty_contact: z.object({
|
||||
button: z
|
||||
.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
})
|
||||
.nullable(),
|
||||
}),
|
||||
})
|
||||
const contentPageSidebarJoinLoyaltyContactRef = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
ContentPageEnum.ContentStack.sidebar.JoinLoyaltyContact
|
||||
),
|
||||
})
|
||||
.merge(joinLoyaltyContactRefsSchema)
|
||||
|
||||
const contentPageSidebarRefsItem = z.discriminatedUnion("__typename", [
|
||||
contentPageSidebarTextContentRef,
|
||||
contentPageSidebarContentRef,
|
||||
contentPageSidebarJoinLoyaltyContactRef,
|
||||
])
|
||||
|
||||
export const validateContentPageRefsSchema = z.object({
|
||||
export const contentPageRefsSchema = z.object({
|
||||
content_page: z.object({
|
||||
blocks: z.array(contentPageBlockRefsItem).nullable(),
|
||||
sidebar: z.array(contentPageSidebarRefsItem).nullable(),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
blocks: discriminatedUnionArray(
|
||||
contentPageBlockRefsItem.options
|
||||
).nullable(),
|
||||
sidebar: discriminatedUnionArray(
|
||||
contentPageSidebarRefsItem.options
|
||||
).nullable(),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -1,49 +1,36 @@
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { GetContentPage } from "@/lib/graphql/Query/ContentPage.graphql"
|
||||
import { GetContentPage } from "@/lib/graphql/Query/ContentPage/ContentPage.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { notFound } from "@/server/errors/trpc"
|
||||
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
|
||||
import { makeImageVaultImage } from "@/utils/imageVault"
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import { removeEmptyObjects } from "../../utils"
|
||||
import { validateContentPageSchema } from "./output"
|
||||
import { contentPageSchema } from "./output"
|
||||
import {
|
||||
fetchContentPageRefs,
|
||||
generatePageTags,
|
||||
getContentPageCounter,
|
||||
makeButtonObject,
|
||||
validateContentPageRefs,
|
||||
} from "./utils"
|
||||
|
||||
import {
|
||||
CardsGridEnum,
|
||||
ContentBlocksTypenameEnum,
|
||||
SidebarTypenameEnum,
|
||||
} from "@/types/components/content/enums"
|
||||
import {
|
||||
TrackingChannelEnum,
|
||||
TrackingSDKPageData,
|
||||
type TrackingSDKPageData,
|
||||
} from "@/types/components/tracking"
|
||||
import {
|
||||
Block,
|
||||
ContentPage,
|
||||
ContentPageDataRaw,
|
||||
Sidebar,
|
||||
} from "@/types/trpc/routers/contentstack/contentPage"
|
||||
import type { GetContentPageSchema } from "@/types/trpc/routers/contentstack/contentPage"
|
||||
|
||||
export const contentPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const cleanedRefsData = await fetchContentPageRefs(lang, uid)
|
||||
const validatedRefsData = validateContentPageRefs(
|
||||
cleanedRefsData,
|
||||
const contentPageRefsData = await fetchContentPageRefs(lang, uid)
|
||||
const contentPageRefs = validateContentPageRefs(
|
||||
contentPageRefsData,
|
||||
lang,
|
||||
uid
|
||||
)
|
||||
const tags = generatePageTags(validatedRefsData, lang)
|
||||
if (!contentPageRefs) {
|
||||
return null
|
||||
}
|
||||
const tags = generatePageTags(contentPageRefs, lang)
|
||||
|
||||
getContentPageCounter.add(1, { lang, uid })
|
||||
console.info(
|
||||
@@ -53,7 +40,7 @@ export const contentPageQueryRouter = router({
|
||||
})
|
||||
)
|
||||
|
||||
const response = await request<ContentPageDataRaw>(
|
||||
const response = await request<GetContentPageSchema>(
|
||||
GetContentPage,
|
||||
{ locale: lang, uid },
|
||||
{
|
||||
@@ -64,154 +51,27 @@ export const contentPageQueryRouter = router({
|
||||
}
|
||||
)
|
||||
|
||||
const { content_page } = removeEmptyObjects(response.data)
|
||||
if (!content_page) {
|
||||
throw notFound(response)
|
||||
}
|
||||
const contentPage = contentPageSchema.safeParse(response.data)
|
||||
|
||||
const processedBlocks = content_page.blocks
|
||||
? content_page.blocks.map((block: any) => {
|
||||
switch (block.__typename) {
|
||||
case ContentBlocksTypenameEnum.ContentPageBlocksContent:
|
||||
return block
|
||||
case ContentBlocksTypenameEnum.ContentPageBlocksShortcuts:
|
||||
return {
|
||||
...block,
|
||||
shortcuts: {
|
||||
...block.shortcuts,
|
||||
shortcuts: block.shortcuts.shortcuts.map((shortcut: any) => ({
|
||||
text: shortcut.text,
|
||||
openInNewTab: shortcut.open_in_new_tab,
|
||||
...shortcut.linkConnection.edges[0].node,
|
||||
url:
|
||||
shortcut.linkConnection.edges[0].node.web?.original_url ||
|
||||
removeMultipleSlashes(
|
||||
`/${shortcut.linkConnection.edges[0].node.system.locale}/${shortcut.linkConnection.edges[0].node.url}`
|
||||
),
|
||||
})),
|
||||
},
|
||||
}
|
||||
case ContentBlocksTypenameEnum.ContentPageBlocksCardsGrid:
|
||||
return {
|
||||
...block,
|
||||
cards_grid: {
|
||||
...block.cards_grid,
|
||||
cards: block.cards_grid.cardConnection.edges.map(
|
||||
({ node: card }: { node: any }) => {
|
||||
switch (card.__typename) {
|
||||
case CardsGridEnum.Card:
|
||||
return {
|
||||
...card,
|
||||
isContentCard: !!card.is_content_card,
|
||||
backgroundImage: makeImageVaultImage(
|
||||
card.background_image
|
||||
),
|
||||
primaryButton: card.has_primary_button
|
||||
? makeButtonObject(card.primary_button)
|
||||
: undefined,
|
||||
secondaryButton: card.has_secondary_button
|
||||
? makeButtonObject(card.secondary_button)
|
||||
: undefined,
|
||||
sidePeekButton:
|
||||
card.has_sidepeek_button ||
|
||||
!!card.sidepeek_button?.call_to_action_text
|
||||
? {
|
||||
title:
|
||||
card.sidepeek_button.call_to_action_text,
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
case CardsGridEnum.LoyaltyCard:
|
||||
return {
|
||||
...card,
|
||||
image: makeImageVaultImage(card.image),
|
||||
link: makeButtonObject(card.link),
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
},
|
||||
}
|
||||
case ContentBlocksTypenameEnum.ContentPageBlocksDynamicContent:
|
||||
return {
|
||||
...block,
|
||||
dynamic_content: {
|
||||
...block.dynamic_content,
|
||||
link: block.dynamic_content.link.pageConnection.edges.length
|
||||
? {
|
||||
text: block.dynamic_content.link.text,
|
||||
href: removeMultipleSlashes(
|
||||
`/${block.dynamic_content.link.pageConnection.edges[0].node.system.locale}/${block.dynamic_content.link.pageConnection.edges[0].node.url}`
|
||||
),
|
||||
title:
|
||||
block.dynamic_content.link.pageConnection.edges[0]
|
||||
.node.title,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
}
|
||||
default:
|
||||
return block
|
||||
}
|
||||
})
|
||||
: null
|
||||
|
||||
const sidebar = response.data.content_page.sidebar
|
||||
? response.data.content_page.sidebar.map((item: any) => {
|
||||
switch (item.__typename) {
|
||||
case SidebarTypenameEnum.ContentPageSidebarJoinLoyaltyContact:
|
||||
return {
|
||||
...item,
|
||||
join_loyalty_contact: {
|
||||
...item.join_loyalty_contact,
|
||||
button: makeButtonObject(item.join_loyalty_contact.button),
|
||||
},
|
||||
}
|
||||
default:
|
||||
return item
|
||||
}
|
||||
})
|
||||
: null
|
||||
|
||||
const heroImage = makeImageVaultImage(content_page.hero_image)
|
||||
const validatedContentPage = validateContentPageSchema.safeParse({
|
||||
content_page: {
|
||||
...content_page,
|
||||
blocks: processedBlocks,
|
||||
sidebar,
|
||||
hero_image: heroImage,
|
||||
},
|
||||
})
|
||||
|
||||
if (!validatedContentPage.success) {
|
||||
if (!contentPage.success) {
|
||||
console.error(
|
||||
`Failed to validate Contentpage Data - (lang: ${lang}, uid: ${uid})`
|
||||
)
|
||||
console.error(validatedContentPage.error?.format())
|
||||
console.error(contentPage.error?.format())
|
||||
return null
|
||||
}
|
||||
|
||||
const { hero_image, blocks, ...restContentPage } =
|
||||
validatedContentPage.data.content_page
|
||||
|
||||
const contentPage: ContentPage = {
|
||||
...restContentPage,
|
||||
heroImage,
|
||||
blocks: blocks as Block[],
|
||||
sidebar: sidebar as Sidebar[],
|
||||
}
|
||||
|
||||
const tracking: TrackingSDKPageData = {
|
||||
pageId: contentPage.system.uid,
|
||||
lang: contentPage.system.locale as Lang,
|
||||
publishedDate: contentPage.system.updated_at,
|
||||
createdDate: contentPage.system.created_at,
|
||||
pageId: contentPage.data.content_page.system.uid,
|
||||
lang: contentPage.data.content_page.system.locale as Lang,
|
||||
publishedDate: contentPage.data.content_page.system.updated_at,
|
||||
createdDate: contentPage.data.content_page.system.created_at,
|
||||
channel: TrackingChannelEnum["static-content-page"],
|
||||
pageType: "staticcontentpage",
|
||||
}
|
||||
|
||||
return {
|
||||
contentPage,
|
||||
contentPage: contentPage.data.content_page,
|
||||
tracking,
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { metrics } from "@opentelemetry/api"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { GetContentPageRefs } from "@/lib/graphql/Query/ContentPage.graphql"
|
||||
import { GetContentPageRefs } from "@/lib/graphql/Query/ContentPage/ContentPage.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { notFound } from "@/server/errors/trpc"
|
||||
|
||||
import { generateTag, generateTags } from "@/utils/generateTag"
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
import { generateTag, generateTagsFromSystem } from "@/utils/generateTag"
|
||||
|
||||
import { removeEmptyObjects } from "../../utils"
|
||||
import { validateContentPageRefsSchema } from "./output"
|
||||
import { contentPageRefsSchema } from "./output"
|
||||
|
||||
import { ContentBlocksTypenameEnum } from "@/types/components/content/enums"
|
||||
import { Edges } from "@/types/requests/utils/edges"
|
||||
import { NodeRefs } from "@/types/requests/utils/refs"
|
||||
import { ContentPageRefsDataRaw } from "@/types/trpc/routers/contentstack/contentPage"
|
||||
import { ContentPageEnum } from "@/types/enums/contentPage"
|
||||
import { System } from "@/types/requests/system"
|
||||
import {
|
||||
ContentPageRefs,
|
||||
GetContentPageRefsSchema,
|
||||
} from "@/types/trpc/routers/contentstack/contentPage"
|
||||
|
||||
const meter = metrics.getMeter("trpc.contentPage")
|
||||
// OpenTelemetry metrics: ContentPage
|
||||
@@ -41,10 +41,15 @@ export async function fetchContentPageRefs(lang: Lang, uid: string) {
|
||||
query: { lang, uid },
|
||||
})
|
||||
)
|
||||
const refsResponse = await request<ContentPageRefsDataRaw>(
|
||||
const refsResponse = await request<GetContentPageRefsSchema>(
|
||||
GetContentPageRefs,
|
||||
{ locale: lang, uid },
|
||||
{ cache: "force-cache", next: { tags: [generateTag(lang, uid)] } }
|
||||
{
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: [generateTag(lang, uid)],
|
||||
},
|
||||
}
|
||||
)
|
||||
if (!refsResponse.data) {
|
||||
const notFoundError = notFound(refsResponse)
|
||||
@@ -69,11 +74,15 @@ export async function fetchContentPageRefs(lang: Lang, uid: string) {
|
||||
throw notFoundError
|
||||
}
|
||||
|
||||
return removeEmptyObjects(refsResponse.data)
|
||||
return refsResponse.data
|
||||
}
|
||||
|
||||
export function validateContentPageRefs(data: any, lang: Lang, uid: string) {
|
||||
const validatedData = validateContentPageRefsSchema.safeParse(data)
|
||||
export function validateContentPageRefs(
|
||||
data: GetContentPageRefsSchema,
|
||||
lang: Lang,
|
||||
uid: string
|
||||
) {
|
||||
const validatedData = contentPageRefsSchema.safeParse(data)
|
||||
if (!validatedData.success) {
|
||||
getContentPageRefsFailCounter.add(1, {
|
||||
lang,
|
||||
@@ -97,64 +106,70 @@ export function validateContentPageRefs(data: any, lang: Lang, uid: string) {
|
||||
query: { lang, uid },
|
||||
})
|
||||
)
|
||||
|
||||
return validatedData.data
|
||||
}
|
||||
|
||||
export function generatePageTags(validatedData: any, lang: Lang): string[] {
|
||||
export function generatePageTags(
|
||||
validatedData: ContentPageRefs,
|
||||
lang: Lang
|
||||
): string[] {
|
||||
const connections = getConnections(validatedData)
|
||||
return [
|
||||
generateTags(lang, connections),
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, validatedData.content_page.system.uid),
|
||||
].flat()
|
||||
}
|
||||
|
||||
export function getConnections(refs: ContentPageRefsDataRaw) {
|
||||
const connections: Edges<NodeRefs>[] = []
|
||||
if (refs.content_page.blocks) {
|
||||
refs.content_page.blocks.forEach((item) => {
|
||||
switch (item.__typename) {
|
||||
case ContentBlocksTypenameEnum.ContentPageBlocksContent: {
|
||||
if (item.content.content.embedded_itemsConnection.edges.length) {
|
||||
connections.push(item.content.content.embedded_itemsConnection)
|
||||
export function getConnections({ content_page }: ContentPageRefs) {
|
||||
const connections: System["system"][] = [content_page.system]
|
||||
if (content_page.blocks) {
|
||||
content_page.blocks.forEach((block) => {
|
||||
switch (block.__typename) {
|
||||
case ContentPageEnum.ContentStack.blocks.Content:
|
||||
{
|
||||
if (block.content.length) {
|
||||
// TS has trouble infering the filtered types
|
||||
// @ts-ignore
|
||||
connections.push(...block.content)
|
||||
}
|
||||
}
|
||||
break
|
||||
case ContentPageEnum.ContentStack.blocks.Shortcuts: {
|
||||
if (block.shortcuts.shortcuts.length) {
|
||||
connections.push(...block.shortcuts.shortcuts)
|
||||
}
|
||||
break
|
||||
}
|
||||
case ContentBlocksTypenameEnum.ContentPageBlocksShortcuts: {
|
||||
item.shortcuts.shortcuts.forEach((shortcut) => {
|
||||
if (shortcut.linkConnection.edges.length) {
|
||||
connections.push(shortcut.linkConnection)
|
||||
}
|
||||
})
|
||||
case ContentPageEnum.ContentStack.blocks.TextCols: {
|
||||
if (block.text_cols.length) {
|
||||
connections.push(...block.text_cols)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (content_page.sidebar) {
|
||||
content_page.sidebar.forEach((block) => {
|
||||
switch (block.__typename) {
|
||||
case ContentPageEnum.ContentStack.sidebar.Content:
|
||||
if (block.content.length) {
|
||||
connections.push(...block.content)
|
||||
}
|
||||
break
|
||||
|
||||
case ContentPageEnum.ContentStack.sidebar.JoinLoyaltyContact:
|
||||
if (block.join_loyalty_contact?.button) {
|
||||
connections.push(block.join_loyalty_contact.button)
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
export function makeButtonObject(button: any) {
|
||||
if (!button) return null
|
||||
|
||||
const isContenstackLink =
|
||||
button?.is_contentstack_link || button.linkConnection?.edges?.length
|
||||
const linkConnnectionNode = isContenstackLink
|
||||
? button.linkConnection.edges[0]?.node
|
||||
: null
|
||||
|
||||
return {
|
||||
openInNewTab: button?.open_in_new_tab,
|
||||
title:
|
||||
button.cta_text ||
|
||||
(linkConnnectionNode
|
||||
? linkConnnectionNode.title
|
||||
: button.external_link.title),
|
||||
href: linkConnnectionNode
|
||||
? linkConnnectionNode.web?.original_url ||
|
||||
removeMultipleSlashes(
|
||||
`/${linkConnnectionNode.system.locale}/${linkConnnectionNode.url}`
|
||||
)
|
||||
: button.external_link.href,
|
||||
isExternal: !isContenstackLink,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +1,26 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { HotelBlocksTypenameEnum } from "@/types/components/hotelPage/enums"
|
||||
import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
|
||||
|
||||
export const activityCardSchema = z.object({
|
||||
background_image: z.any(),
|
||||
cta_text: z.string(),
|
||||
heading: z.string(),
|
||||
open_in_new_tab: z.boolean(),
|
||||
scripted_title: z.string().optional(),
|
||||
body_text: z.string(),
|
||||
hotel_page_activities_content_pageConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
url: z.string(),
|
||||
web: z.object({
|
||||
original_url: z.string().optional(),
|
||||
}),
|
||||
system: z.object({
|
||||
locale: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
import { activitiesCard } from "../schemas/blocks/activitiesCard"
|
||||
|
||||
const contentBlockActivity = z.object({
|
||||
__typename: z.literal(
|
||||
HotelBlocksTypenameEnum.HotelPageContentUpcomingActivitiesCard
|
||||
),
|
||||
upcoming_activities_card: activityCardSchema,
|
||||
})
|
||||
import { HotelPageEnum } from "@/types/enums/hotelPage"
|
||||
|
||||
const contentBlockItem = z.discriminatedUnion("__typename", [
|
||||
contentBlockActivity,
|
||||
const contentBlockActivities = z
|
||||
.object({
|
||||
__typename: z.literal(HotelPageEnum.ContentStack.blocks.ActivitiesCard),
|
||||
})
|
||||
.merge(activitiesCard)
|
||||
|
||||
export const contentBlock = z.discriminatedUnion("__typename", [
|
||||
contentBlockActivities,
|
||||
])
|
||||
|
||||
export const validateHotelPageSchema = z.object({
|
||||
hotel_page: z.object({
|
||||
hotel_page_id: z.string(),
|
||||
title: z.string(),
|
||||
url: z.string(),
|
||||
content: z.array(contentBlockItem).nullable(),
|
||||
}),
|
||||
})
|
||||
|
||||
export const hotelPageSchema = z.object({
|
||||
hotel_page: z.object({
|
||||
content: discriminatedUnionArray(contentBlock.options).nullable(),
|
||||
hotel_page_id: z.string(),
|
||||
title: z.string(),
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
// Will be extended once we introduce more functionality to our entries.
|
||||
export type HotelPageDataRaw = z.infer<typeof validateHotelPageSchema>
|
||||
|
||||
type HotelPageRaw = HotelPageDataRaw["hotel_page"]
|
||||
export type HotelPage = HotelPageRaw
|
||||
|
||||
export type ActivityCard = z.infer<typeof activityCardSchema>
|
||||
export type ContentBlockItem = z.infer<typeof contentBlockItem>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { metrics } from "@opentelemetry/api"
|
||||
|
||||
import { GetHotelPage } from "@/lib/graphql/Query/HotelPage.graphql"
|
||||
import { GetHotelPage } from "@/lib/graphql/Query/HotelPage/HotelPage.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { notFound } from "@/server/errors/trpc"
|
||||
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
|
||||
import { generateTag } from "@/utils/generateTag"
|
||||
|
||||
import { HotelPage, HotelPageDataRaw, validateHotelPageSchema } from "./output"
|
||||
import { hotelPageSchema } from "./output"
|
||||
|
||||
import { GetHotelPageData } from "@/types/trpc/routers/contentstack/hotelPage"
|
||||
|
||||
// OpenTelemetry metrics
|
||||
const meter = metrics.getMeter("trpc.contentstack.hotelPage")
|
||||
@@ -31,7 +33,7 @@ export const hotelPageQueryRouter = router({
|
||||
query: { lang, uid },
|
||||
})
|
||||
)
|
||||
const response = await request<HotelPageDataRaw>(
|
||||
const response = await request<GetHotelPageData>(
|
||||
GetHotelPage,
|
||||
{
|
||||
locale: lang,
|
||||
@@ -62,7 +64,7 @@ export const hotelPageQueryRouter = router({
|
||||
throw notFoundError
|
||||
}
|
||||
|
||||
const validatedHotelPage = validateHotelPageSchema.safeParse(response.data)
|
||||
const validatedHotelPage = hotelPageSchema.safeParse(response.data)
|
||||
|
||||
if (!validatedHotelPage.success) {
|
||||
getHotelPageFailCounter.add(1, {
|
||||
@@ -81,9 +83,6 @@ export const hotelPageQueryRouter = router({
|
||||
return null
|
||||
}
|
||||
|
||||
const hotelPage = {
|
||||
...validatedHotelPage.data.hotel_page,
|
||||
} as HotelPage
|
||||
getHotelPageSuccessCounter.add(1, { lang, uid: `${uid}` })
|
||||
console.info(
|
||||
"contentstack.hotelPage success",
|
||||
@@ -91,6 +90,6 @@ export const hotelPageQueryRouter = router({
|
||||
query: { lang, uid },
|
||||
})
|
||||
)
|
||||
return hotelPage
|
||||
return validatedHotelPage.data.hotel_page
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ import { z } from "zod"
|
||||
|
||||
const link = z
|
||||
.object({ url: z.string().optional(), isExternal: z.boolean() })
|
||||
.optional()
|
||||
.nullable()
|
||||
|
||||
export const validateLanguageSwitcherData = z.object({
|
||||
|
||||
@@ -6,23 +6,23 @@ import { batchRequest } from "@/lib/graphql/batchRequest"
|
||||
import {
|
||||
GetDaDeEnUrlsAccountPage,
|
||||
GetFiNoSvUrlsAccountPage,
|
||||
} from "@/lib/graphql/Query/AccountPage.graphql"
|
||||
} from "@/lib/graphql/Query/AccountPage/AccountPage.graphql"
|
||||
import {
|
||||
GetDaDeEnUrlsContentPage,
|
||||
GetFiNoSvUrlsContentPage,
|
||||
} from "@/lib/graphql/Query/ContentPage.graphql"
|
||||
import {
|
||||
GetDaDeEnUrlsHotelPage,
|
||||
GetFiNoSvUrlsHotelPage,
|
||||
} from "@/lib/graphql/Query/HotelPage.graphql"
|
||||
} from "@/lib/graphql/Query/ContentPage/ContentPage.graphql"
|
||||
import {
|
||||
GetDaDeEnUrlsCurrentBlocksPage,
|
||||
GetFiNoSvUrlsCurrentBlocksPage,
|
||||
} from "@/lib/graphql/Query/LanguageSwitcherCurrent.graphql"
|
||||
} from "@/lib/graphql/Query/Current/LanguageSwitcher.graphql"
|
||||
import {
|
||||
GetDaDeEnUrlsHotelPage,
|
||||
GetFiNoSvUrlsHotelPage,
|
||||
} from "@/lib/graphql/Query/HotelPage/HotelPage.graphql"
|
||||
import {
|
||||
GetDaDeEnUrlsLoyaltyPage,
|
||||
GetFiNoSvUrlsLoyaltyPage,
|
||||
} from "@/lib/graphql/Query/LoyaltyPage.graphql"
|
||||
} from "@/lib/graphql/Query/LoyaltyPage/LoyaltyPage.graphql"
|
||||
import { internalServerError } from "@/server/errors/trpc"
|
||||
import { publicProcedure, router } from "@/server/trpc"
|
||||
|
||||
@@ -65,128 +65,61 @@ async function getLanguageSwitcher(options: LanguageSwitcherVariables) {
|
||||
generateTag(Lang.no, options.uid, languageSwitcherAffix),
|
||||
generateTag(Lang.sv, options.uid, languageSwitcherAffix),
|
||||
]
|
||||
let daDeEnDocument = null
|
||||
let fiNoSvDocument = null
|
||||
switch (options.contentType) {
|
||||
case PageTypeEnum.accountPage:
|
||||
return await batchRequest<LanguageSwitcherQueryDataRaw>([
|
||||
{
|
||||
document: GetDaDeEnUrlsAccountPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsDaDeEn,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
document: GetFiNoSvUrlsAccountPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsFiNoSv,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
daDeEnDocument = GetDaDeEnUrlsAccountPage
|
||||
fiNoSvDocument = GetFiNoSvUrlsAccountPage
|
||||
break
|
||||
case PageTypeEnum.currentBlocksPage:
|
||||
return await batchRequest<LanguageSwitcherQueryDataRaw>([
|
||||
{
|
||||
document: GetDaDeEnUrlsCurrentBlocksPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsDaDeEn,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
document: GetFiNoSvUrlsCurrentBlocksPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsFiNoSv,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
daDeEnDocument = GetDaDeEnUrlsCurrentBlocksPage
|
||||
fiNoSvDocument = GetFiNoSvUrlsCurrentBlocksPage
|
||||
break
|
||||
case PageTypeEnum.loyaltyPage:
|
||||
return await batchRequest<LanguageSwitcherQueryDataRaw>([
|
||||
{
|
||||
document: GetDaDeEnUrlsLoyaltyPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsDaDeEn,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
document: GetFiNoSvUrlsLoyaltyPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsFiNoSv,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
daDeEnDocument = GetDaDeEnUrlsLoyaltyPage
|
||||
fiNoSvDocument = GetFiNoSvUrlsLoyaltyPage
|
||||
break
|
||||
case PageTypeEnum.hotelPage:
|
||||
return await batchRequest<LanguageSwitcherQueryDataRaw>([
|
||||
{
|
||||
document: GetDaDeEnUrlsHotelPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsDaDeEn,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
document: GetFiNoSvUrlsHotelPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsFiNoSv,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
daDeEnDocument = GetDaDeEnUrlsHotelPage
|
||||
fiNoSvDocument = GetFiNoSvUrlsHotelPage
|
||||
break
|
||||
case PageTypeEnum.contentPage:
|
||||
return await batchRequest<LanguageSwitcherQueryDataRaw>([
|
||||
{
|
||||
document: GetDaDeEnUrlsContentPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsDaDeEn,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
document: GetFiNoSvUrlsContentPage,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsFiNoSv,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
daDeEnDocument = GetDaDeEnUrlsContentPage
|
||||
fiNoSvDocument = GetFiNoSvUrlsContentPage
|
||||
break
|
||||
default:
|
||||
console.error(`type: [${options.contentType}]`)
|
||||
console.error(`Trying to get a content type that is not supported`)
|
||||
throw internalServerError()
|
||||
}
|
||||
|
||||
if (daDeEnDocument && fiNoSvDocument) {
|
||||
return await batchRequest<LanguageSwitcherQueryDataRaw>([
|
||||
{
|
||||
document: daDeEnDocument,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsDaDeEn,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
document: fiNoSvDocument,
|
||||
variables,
|
||||
options: {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: tagsFiNoSv,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
throw internalServerError()
|
||||
}
|
||||
|
||||
export const languageSwitcherQueryRouter = router({
|
||||
@@ -213,9 +146,10 @@ export const languageSwitcherQueryRouter = router({
|
||||
contentType: ctx.contentType!,
|
||||
uid: ctx.uid,
|
||||
})
|
||||
|
||||
const urls = Object.keys(res.data).reduce<LanguageSwitcherData>(
|
||||
(acc, key) => {
|
||||
const item = res.data[key as Lang]?.items[0]
|
||||
const item = res.data[key as Lang]
|
||||
const url = item
|
||||
? item.web?.original_url || `/${key}${item.url}`
|
||||
: undefined
|
||||
|
||||
@@ -1,432 +1,192 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
|
||||
|
||||
import { imageVaultAssetSchema } from "../schemas/imageVault"
|
||||
|
||||
import { ImageVaultAsset } from "@/types/components/imageVault"
|
||||
import {
|
||||
JoinLoyaltyContactTypenameEnum,
|
||||
LoyaltyBlocksTypenameEnum,
|
||||
LoyaltyCardsGridEnum,
|
||||
LoyaltyComponentEnum,
|
||||
LoyaltySidebarDynamicComponentEnum,
|
||||
SidebarTypenameEnum,
|
||||
} from "@/types/components/loyalty/enums"
|
||||
import { Embeds } from "@/types/requests/embeds"
|
||||
import { PageLinkEnum } from "@/types/requests/pageLinks"
|
||||
import { RTEEmbedsEnum } from "@/types/requests/rte"
|
||||
import { EdgesWithTotalCount } from "@/types/requests/utils/edges"
|
||||
import { RTEDocument } from "@/types/rte/node"
|
||||
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 { tempImageVaultAssetSchema } from "../schemas/imageVault"
|
||||
import {
|
||||
contentRefsSchema as sidebarContentRefsSchema,
|
||||
contentSchema as sidebarContentSchema,
|
||||
} from "../schemas/sidebar/content"
|
||||
import { dynamicContentSchema as sidebarDynamicContentSchema } from "../schemas/sidebar/dynamicContent"
|
||||
import {
|
||||
joinLoyaltyContactRefsSchema,
|
||||
joinLoyaltyContactSchema,
|
||||
} from "../schemas/sidebar/joinLoyaltyContact"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
const loyaltyPageDynamicContent = z.object({
|
||||
__typename: z.literal(
|
||||
LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent
|
||||
),
|
||||
dynamic_content: z.object({
|
||||
title: z.string().nullable(),
|
||||
subtitle: z.string().nullable(),
|
||||
component: z.nativeEnum(LoyaltyComponentEnum),
|
||||
link: z
|
||||
.object({
|
||||
text: z.string(),
|
||||
href: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
})
|
||||
import { LoyaltyPageEnum } from "@/types/enums/loyaltyPage"
|
||||
|
||||
const loyaltyPageShortcuts = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksShortcuts),
|
||||
shortcuts: z.object({
|
||||
title: z.string().nullable(),
|
||||
preamble: z.string().nullable(),
|
||||
shortcuts: z.array(
|
||||
z.object({
|
||||
text: z.string().optional(),
|
||||
openInNewTab: z.boolean(),
|
||||
url: z.string(),
|
||||
title: z.string(),
|
||||
})
|
||||
// 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 cardBlock = z.object({
|
||||
__typename: z.literal(LoyaltyCardsGridEnum.Card),
|
||||
heading: z.string().nullable(),
|
||||
body_text: z.string().nullable(),
|
||||
background_image: z.any(),
|
||||
scripted_top_title: z.string().nullable(),
|
||||
primaryButton: z
|
||||
.object({
|
||||
openInNewTab: z.boolean(),
|
||||
title: z.string(),
|
||||
href: z.string(),
|
||||
isExternal: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
secondaryButton: z
|
||||
.object({
|
||||
openInNewTab: z.boolean(),
|
||||
title: z.string(),
|
||||
href: z.string(),
|
||||
isExternal: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
system: z.object({
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
const sidebarRefsSchema = z.discriminatedUnion("__typename", [
|
||||
contentSidebarRefsSchema,
|
||||
extendedJoinLoyaltyContactRefsSchema,
|
||||
z.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.sidebar.DynamicContent),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyCardBlock = z.object({
|
||||
__typename: z.literal(LoyaltyCardsGridEnum.LoyaltyCard),
|
||||
heading: z.string().nullable(),
|
||||
body_text: z.string().nullable(),
|
||||
image: z.any(),
|
||||
link: z
|
||||
.object({
|
||||
openInNewTab: z.boolean(),
|
||||
title: z.string(),
|
||||
href: z.string(),
|
||||
isExternal: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
system: z.object({
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageCardsItems = z.discriminatedUnion("__typename", [
|
||||
loyaltyCardBlock,
|
||||
cardBlock,
|
||||
])
|
||||
|
||||
const loyaltyPageCards = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid),
|
||||
cards_grid: z.object({
|
||||
title: z.string().nullable(),
|
||||
preamble: z.string().nullable(),
|
||||
layout: z.enum(["twoColumnGrid", "threeColumnGrid", "twoPlusOne"]),
|
||||
theme: z.enum(["one", "two", "three"]).nullable(),
|
||||
cards: z.array(loyaltyPageCardsItems),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageBlockTextContent = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(z.any()),
|
||||
totalCount: z.number(),
|
||||
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
|
||||
}),
|
||||
json: z.any(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageBlockItem = z.discriminatedUnion("__typename", [
|
||||
loyaltyPageDynamicContent,
|
||||
loyaltyPageBlockTextContent,
|
||||
loyaltyPageShortcuts,
|
||||
loyaltyPageCards,
|
||||
// LoyaltyPage
|
||||
export const extendedCardsGridSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.blocks.CardsGrid),
|
||||
})
|
||||
.merge(cardsGridSchema)
|
||||
|
||||
export const extendedContentSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.blocks.Content),
|
||||
})
|
||||
.merge(blockContentSchema)
|
||||
|
||||
export const extendedDynamicContentSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.blocks.DynamicContent),
|
||||
})
|
||||
.merge(blockDynamicContentSchema)
|
||||
|
||||
export const extendedShortcutsSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.blocks.Shortcuts),
|
||||
})
|
||||
.merge(shortcutsSchema)
|
||||
|
||||
export const blocksSchema = z.discriminatedUnion("__typename", [
|
||||
extendedCardsGridSchema,
|
||||
extendedContentSchema,
|
||||
extendedDynamicContentSchema,
|
||||
extendedShortcutsSchema,
|
||||
])
|
||||
|
||||
const loyaltyPageSidebarTextContent = z.object({
|
||||
__typename: z.literal(SidebarTypenameEnum.LoyaltyPageSidebarContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(z.any()),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
json: z.any(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
const contentSidebarSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.sidebar.Content),
|
||||
})
|
||||
.merge(sidebarContentSchema)
|
||||
|
||||
const loyaltyPageJoinLoyaltyContact = z.object({
|
||||
__typename: z.literal(
|
||||
SidebarTypenameEnum.LoyaltyPageSidebarJoinLoyaltyContact
|
||||
),
|
||||
join_loyalty_contact: z.object({
|
||||
title: z.string().nullable(),
|
||||
preamble: z.string().nullable(),
|
||||
button: z
|
||||
.object({
|
||||
openInNewTab: z.boolean(),
|
||||
title: z.string(),
|
||||
href: z.string(),
|
||||
isExternal: z.boolean(),
|
||||
})
|
||||
.nullable(),
|
||||
contact: z.array(
|
||||
z.object({
|
||||
__typename: z.literal(
|
||||
JoinLoyaltyContactTypenameEnum.LoyaltyPageSidebarJoinLoyaltyContactBlockContactContact
|
||||
),
|
||||
contact: z.object({
|
||||
display_text: z.string().nullable(),
|
||||
contact_field: z.string(),
|
||||
footnote: z.string().nullable(),
|
||||
}),
|
||||
})
|
||||
const dynamicContentSidebarSchema = z
|
||||
.object({
|
||||
__typename: z.literal(LoyaltyPageEnum.ContentStack.sidebar.DynamicContent),
|
||||
})
|
||||
.merge(sidebarDynamicContentSchema)
|
||||
|
||||
export const joinLoyaltyContactSidebarSchema = z
|
||||
.object({
|
||||
__typename: z.literal(
|
||||
LoyaltyPageEnum.ContentStack.sidebar.JoinLoyaltyContact
|
||||
),
|
||||
}),
|
||||
})
|
||||
})
|
||||
.merge(joinLoyaltyContactSchema)
|
||||
|
||||
const loyaltyPageSidebarDynamicContent = z.object({
|
||||
__typename: z.literal(SidebarTypenameEnum.LoyaltyPageSidebarDynamicContent),
|
||||
dynamic_content: z.object({
|
||||
component: z.nativeEnum(LoyaltySidebarDynamicComponentEnum),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageSidebarItem = z.discriminatedUnion("__typename", [
|
||||
loyaltyPageSidebarTextContent,
|
||||
loyaltyPageSidebarDynamicContent,
|
||||
loyaltyPageJoinLoyaltyContact,
|
||||
export const sidebarSchema = z.discriminatedUnion("__typename", [
|
||||
contentSidebarSchema,
|
||||
dynamicContentSidebarSchema,
|
||||
joinLoyaltyContactSidebarSchema,
|
||||
])
|
||||
|
||||
export const validateLoyaltyPageSchema = z.object({
|
||||
heading: z.string().nullable(),
|
||||
preamble: z.string().nullable(),
|
||||
hero_image: imageVaultAssetSchema.nullable().optional(),
|
||||
blocks: z.array(loyaltyPageBlockItem).nullable(),
|
||||
sidebar: z.array(loyaltyPageSidebarItem).nullable(),
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
// Block types
|
||||
export type DynamicContent = z.infer<typeof loyaltyPageDynamicContent>
|
||||
|
||||
type BlockContentRaw = z.infer<typeof loyaltyPageBlockTextContent>
|
||||
export interface RteBlockContent extends BlockContentRaw {
|
||||
content: {
|
||||
content: {
|
||||
json: RTEDocument
|
||||
embedded_itemsConnection: EdgesWithTotalCount<Embeds>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type LoyaltyCardRaw = z.infer<typeof loyaltyCardBlock>
|
||||
|
||||
type LoyaltyCard = Omit<LoyaltyCardRaw, "image"> & {
|
||||
image?: ImageVaultAsset
|
||||
}
|
||||
|
||||
type CardRaw = z.infer<typeof cardBlock>
|
||||
|
||||
type Card = Omit<CardRaw, "background_image"> & {
|
||||
backgroundImage?: ImageVaultAsset
|
||||
}
|
||||
|
||||
type CardsGridRaw = z.infer<typeof loyaltyPageCards>
|
||||
|
||||
export type CardsGrid = Omit<CardsGridRaw, "cards"> & {
|
||||
cards: (LoyaltyCard | Card)[]
|
||||
}
|
||||
|
||||
export type CardsRaw = CardsGrid["cards_grid"]["cards"][number]
|
||||
|
||||
export type Shortcuts = z.infer<typeof loyaltyPageShortcuts>
|
||||
|
||||
export type Block = RteBlockContent | DynamicContent | Shortcuts | CardsGrid
|
||||
|
||||
// Sidebar block types
|
||||
type SidebarContentRaw = z.infer<typeof loyaltyPageSidebarTextContent>
|
||||
|
||||
export type RteSidebarContent = Omit<SidebarContentRaw, "content"> & {
|
||||
content: {
|
||||
content: {
|
||||
json: RTEDocument
|
||||
embedded_itemsConnection: EdgesWithTotalCount<Embeds>
|
||||
}
|
||||
}
|
||||
}
|
||||
type SideBarDynamicContent = z.infer<typeof loyaltyPageSidebarDynamicContent>
|
||||
|
||||
export type JoinLoyaltyContact = z.infer<typeof loyaltyPageJoinLoyaltyContact>
|
||||
export type Sidebar =
|
||||
| JoinLoyaltyContact
|
||||
| RteSidebarContent
|
||||
| SideBarDynamicContent
|
||||
type LoyaltyPageDataRaw = z.infer<typeof validateLoyaltyPageSchema>
|
||||
|
||||
export type LoyaltyPage = Omit<
|
||||
LoyaltyPageDataRaw,
|
||||
"blocks" | "sidebar" | "hero_image"
|
||||
> & {
|
||||
heroImage?: ImageVaultAsset
|
||||
blocks: Block[]
|
||||
sidebar: Sidebar[]
|
||||
}
|
||||
|
||||
// Refs types
|
||||
const pageConnectionRefs = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
__typename: z.nativeEnum(PageLinkEnum),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
const rteConnectionRefs = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
__typename: z.nativeEnum(RTEEmbedsEnum),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
const cardBlockRefs = z.object({
|
||||
__typename: z.literal(LoyaltyCardsGridEnum.Card),
|
||||
primary_button: z
|
||||
export const loyaltyPageSchema = z.object({
|
||||
loyalty_page: z
|
||||
.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
})
|
||||
.nullable(),
|
||||
secondary_button: z
|
||||
.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
})
|
||||
.nullable(),
|
||||
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyCardBlockRefs = z.object({
|
||||
__typename: z.literal(LoyaltyCardsGridEnum.LoyaltyCard),
|
||||
link: z
|
||||
.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
})
|
||||
.nullable(),
|
||||
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
const cardGridCardsRef = z.discriminatedUnion("__typename", [
|
||||
loyaltyCardBlockRefs,
|
||||
cardBlockRefs,
|
||||
])
|
||||
|
||||
const loyaltyPageCardsRefs = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid),
|
||||
cards_grid: z.object({
|
||||
cardConnection: z.object({
|
||||
edges: z.array(
|
||||
blocks: discriminatedUnionArray(blocksSchema.options).nullable(),
|
||||
heading: z.string().optional(),
|
||||
hero_image: tempImageVaultAssetSchema,
|
||||
preamble: z.string().optional(),
|
||||
sidebar: discriminatedUnionArray(sidebarSchema.options).nullable(),
|
||||
title: z.string().optional(),
|
||||
system: systemSchema.merge(
|
||||
z.object({
|
||||
node: cardGridCardsRef,
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
})
|
||||
),
|
||||
})
|
||||
.transform((data) => {
|
||||
return {
|
||||
blocks: data.blocks ? data.blocks : [],
|
||||
heading: data.heading,
|
||||
heroImage: data.hero_image,
|
||||
preamble: data.preamble,
|
||||
sidebar: data.sidebar ? data.sidebar : [],
|
||||
system: data.system,
|
||||
}
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageDynamicContentRefs = z.object({
|
||||
__typename: z.literal(
|
||||
LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent
|
||||
),
|
||||
dynamic_content: z.object({
|
||||
link: z.object({
|
||||
pageConnection: pageConnectionRefs,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageShortcutsRefs = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksShortcuts),
|
||||
shortcuts: z.object({
|
||||
shortcuts: z.array(
|
||||
z.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageBlockTextContentRefs = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: rteConnectionRefs,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageBlocRefsItem = z.discriminatedUnion("__typename", [
|
||||
loyaltyPageDynamicContentRefs,
|
||||
loyaltyPageBlockTextContentRefs,
|
||||
loyaltyPageShortcutsRefs,
|
||||
loyaltyPageCardsRefs,
|
||||
])
|
||||
|
||||
const loyaltyPageSidebarTextContentRef = z.object({
|
||||
__typename: z.literal(SidebarTypenameEnum.LoyaltyPageSidebarContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: rteConnectionRefs,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageSidebarJoinLoyaltyContactRef = z.object({
|
||||
__typename: z.literal(
|
||||
SidebarTypenameEnum.LoyaltyPageSidebarJoinLoyaltyContact
|
||||
),
|
||||
join_loyalty_contact: z.object({
|
||||
button: z
|
||||
.object({
|
||||
linkConnection: pageConnectionRefs,
|
||||
})
|
||||
.nullable(),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageSidebarRefsItem = z.discriminatedUnion("__typename", [
|
||||
loyaltyPageSidebarTextContentRef,
|
||||
loyaltyPageSidebarJoinLoyaltyContactRef,
|
||||
])
|
||||
|
||||
export const validateLoyaltyPageRefsSchema = z.object({
|
||||
loyalty_page: z.object({
|
||||
blocks: z.array(loyaltyPageBlocRefsItem).nullable(),
|
||||
sidebar: z.array(loyaltyPageSidebarRefsItem).nullable(),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export type LoyaltyPageRefsDataRaw = z.infer<
|
||||
typeof validateLoyaltyPageRefsSchema
|
||||
>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Lang } from "@/constants/languages"
|
||||
import {
|
||||
GetLoyaltyPage,
|
||||
GetLoyaltyPageRefs,
|
||||
} from "@/lib/graphql/Query/LoyaltyPage.graphql"
|
||||
} from "@/lib/graphql/Query/LoyaltyPage/LoyaltyPage.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { notFound } from "@/server/errors/trpc"
|
||||
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
@@ -12,28 +12,20 @@ import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTags,
|
||||
generateTagsFromSystem,
|
||||
} from "@/utils/generateTag"
|
||||
import { makeImageVaultImage } from "@/utils/imageVault"
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import { removeEmptyObjects } from "../../utils"
|
||||
import {
|
||||
type LoyaltyPageRefsDataRaw,
|
||||
validateLoyaltyPageRefsSchema,
|
||||
validateLoyaltyPageSchema,
|
||||
} from "./output"
|
||||
import { getConnections, makeButtonObject } from "./utils"
|
||||
import { loyaltyPageRefsSchema, loyaltyPageSchema } from "./output"
|
||||
import { getConnections } from "./utils"
|
||||
|
||||
import {
|
||||
LoyaltyBlocksTypenameEnum,
|
||||
LoyaltyCardsGridEnum,
|
||||
SidebarTypenameEnum,
|
||||
} from "@/types/components/loyalty/enums"
|
||||
import {
|
||||
TrackingChannelEnum,
|
||||
TrackingSDKPageData,
|
||||
} from "@/types/components/tracking"
|
||||
import type {
|
||||
GetLoyaltyPageRefsSchema,
|
||||
GetLoyaltyPageSchema,
|
||||
} from "@/types/trpc/routers/contentstack/loyaltyPage"
|
||||
|
||||
const meter = metrics.getMeter("trpc.loyaltyPage")
|
||||
// OpenTelemetry metrics: LoyaltyPage
|
||||
@@ -59,19 +51,18 @@ const getLoyaltyPageFailCounter = meter.createCounter(
|
||||
export const loyaltyPageQueryRouter = router({
|
||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
getLoyaltyPageRefsCounter.add(1, { lang, uid })
|
||||
const metricsVariables = { lang, uid }
|
||||
const variables = { locale: lang, uid }
|
||||
getLoyaltyPageRefsCounter.add(1, metricsVariables)
|
||||
console.info(
|
||||
"contentstack.loyaltyPage.refs start",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
query: metricsVariables,
|
||||
})
|
||||
)
|
||||
const refsResponse = await request<LoyaltyPageRefsDataRaw>(
|
||||
const refsResponse = await request<GetLoyaltyPageRefsSchema>(
|
||||
GetLoyaltyPageRefs,
|
||||
{
|
||||
locale: lang,
|
||||
uid,
|
||||
},
|
||||
variables,
|
||||
{
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
@@ -83,8 +74,7 @@ export const loyaltyPageQueryRouter = router({
|
||||
if (!refsResponse.data) {
|
||||
const notFoundError = notFound(refsResponse)
|
||||
getLoyaltyPageRefsFailCounter.add(1, {
|
||||
lang,
|
||||
uid,
|
||||
...metricsVariables,
|
||||
error_type: "http_error",
|
||||
error: JSON.stringify({
|
||||
code: notFoundError.code,
|
||||
@@ -93,222 +83,111 @@ export const loyaltyPageQueryRouter = router({
|
||||
console.error(
|
||||
"contentstack.loyaltyPage.refs not found error",
|
||||
JSON.stringify({
|
||||
query: {
|
||||
lang,
|
||||
uid,
|
||||
},
|
||||
query: metricsVariables,
|
||||
error: { code: notFoundError.code },
|
||||
})
|
||||
)
|
||||
throw notFoundError
|
||||
}
|
||||
|
||||
const cleanedData = removeEmptyObjects(refsResponse.data)
|
||||
|
||||
const validatedLoyaltyPageRefs =
|
||||
validateLoyaltyPageRefsSchema.safeParse(cleanedData)
|
||||
const validatedLoyaltyPageRefs = loyaltyPageRefsSchema.safeParse(
|
||||
refsResponse.data
|
||||
)
|
||||
if (!validatedLoyaltyPageRefs.success) {
|
||||
getLoyaltyPageRefsFailCounter.add(1, {
|
||||
lang,
|
||||
uid,
|
||||
...metricsVariables,
|
||||
error_type: "validation_error",
|
||||
error: JSON.stringify(validatedLoyaltyPageRefs.error),
|
||||
})
|
||||
console.error(
|
||||
"contentstack.loyaltyPage.refs validation error",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
query: metricsVariables,
|
||||
error: validatedLoyaltyPageRefs.error,
|
||||
})
|
||||
)
|
||||
return null
|
||||
}
|
||||
getLoyaltyPageRefsSuccessCounter.add(1, { lang, uid })
|
||||
getLoyaltyPageRefsSuccessCounter.add(1, metricsVariables)
|
||||
console.info(
|
||||
"contentstack.loyaltyPage.refs success",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
query: metricsVariables,
|
||||
})
|
||||
)
|
||||
|
||||
const connections = getConnections(validatedLoyaltyPageRefs.data)
|
||||
|
||||
const tags = [
|
||||
generateTags(lang, connections),
|
||||
generateTagsFromSystem(lang, connections),
|
||||
generateTag(lang, validatedLoyaltyPageRefs.data.loyalty_page.system.uid),
|
||||
].flat()
|
||||
getLoyaltyPageCounter.add(1, { lang, uid })
|
||||
getLoyaltyPageCounter.add(1, metricsVariables)
|
||||
console.info(
|
||||
"contentstack.loyaltyPage start",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
query: metricsVariables,
|
||||
})
|
||||
)
|
||||
const response = await request<any>(
|
||||
const response = await request<GetLoyaltyPageSchema>(
|
||||
GetLoyaltyPage,
|
||||
{
|
||||
locale: lang,
|
||||
uid,
|
||||
},
|
||||
variables,
|
||||
{
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags,
|
||||
},
|
||||
next: { tags },
|
||||
}
|
||||
)
|
||||
|
||||
if (!response.data) {
|
||||
const notFoundError = notFound(response)
|
||||
getLoyaltyPageFailCounter.add(1, {
|
||||
lang,
|
||||
uid,
|
||||
...metricsVariables,
|
||||
error_type: "http_error",
|
||||
error: JSON.stringify({ code: notFoundError.code }),
|
||||
})
|
||||
console.error(
|
||||
"contentstack.loyaltyPage not found error",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
query: metricsVariables,
|
||||
error: { code: notFoundError.code },
|
||||
})
|
||||
)
|
||||
throw notFound(response)
|
||||
}
|
||||
|
||||
const blocks = response.data.loyalty_page.blocks
|
||||
? response.data.loyalty_page.blocks.map((block: any) => {
|
||||
switch (block.__typename) {
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent:
|
||||
return {
|
||||
...block,
|
||||
dynamic_content: {
|
||||
...block.dynamic_content,
|
||||
link: block.dynamic_content.link.pageConnection.edges.length
|
||||
? {
|
||||
text: block.dynamic_content.link.text,
|
||||
href: removeMultipleSlashes(
|
||||
`/${block.dynamic_content.link.pageConnection.edges[0].node.system.locale}/${block.dynamic_content.link.pageConnection.edges[0].node.url}`
|
||||
),
|
||||
title:
|
||||
block.dynamic_content.link.pageConnection.edges[0]
|
||||
.node.title,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
}
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksShortcuts:
|
||||
return {
|
||||
...block,
|
||||
shortcuts: {
|
||||
...block.shortcuts,
|
||||
shortcuts: block.shortcuts.shortcuts.map((shortcut: any) => ({
|
||||
text: shortcut.text,
|
||||
openInNewTab: shortcut.open_in_new_tab,
|
||||
...shortcut.linkConnection.edges[0].node,
|
||||
url:
|
||||
shortcut.linkConnection.edges[0].node.web?.original_url ||
|
||||
removeMultipleSlashes(
|
||||
`/${shortcut.linkConnection.edges[0].node.system.locale}/${shortcut.linkConnection.edges[0].node.url}`
|
||||
),
|
||||
})),
|
||||
},
|
||||
}
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid:
|
||||
return {
|
||||
...block,
|
||||
cards_grid: {
|
||||
...block.cards_grid,
|
||||
cards: block.cards_grid.cardConnection.edges.map(
|
||||
({ node: card }: { node: any }) => {
|
||||
switch (card.__typename) {
|
||||
case LoyaltyCardsGridEnum.LoyaltyCard:
|
||||
return {
|
||||
...card,
|
||||
image: makeImageVaultImage(card.image),
|
||||
link: makeButtonObject(card.link),
|
||||
}
|
||||
case LoyaltyCardsGridEnum.Card:
|
||||
return {
|
||||
...card,
|
||||
backgroundImage: makeImageVaultImage(
|
||||
card.background_image
|
||||
),
|
||||
primaryButton: card.has_primary_button
|
||||
? makeButtonObject(card.primary_button)
|
||||
: undefined,
|
||||
secondaryButton: card.has_secondary_button
|
||||
? makeButtonObject(card.secondary_button)
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
},
|
||||
}
|
||||
default:
|
||||
return block
|
||||
}
|
||||
})
|
||||
: null
|
||||
|
||||
const sidebar = response.data.loyalty_page.sidebar
|
||||
? response.data.loyalty_page.sidebar.map((item: any) => {
|
||||
switch (item.__typename) {
|
||||
case SidebarTypenameEnum.LoyaltyPageSidebarJoinLoyaltyContact:
|
||||
return {
|
||||
...item,
|
||||
join_loyalty_contact: {
|
||||
...item.join_loyalty_contact,
|
||||
button: makeButtonObject(item.join_loyalty_contact.button),
|
||||
},
|
||||
}
|
||||
default:
|
||||
return item
|
||||
}
|
||||
})
|
||||
: null
|
||||
|
||||
const loyaltyPage = {
|
||||
heading: response.data.loyalty_page.heading,
|
||||
preamble: response.data.loyalty_page.preamble,
|
||||
heroImage: makeImageVaultImage(response.data.loyalty_page.hero_image),
|
||||
system: response.data.loyalty_page.system,
|
||||
blocks,
|
||||
sidebar,
|
||||
}
|
||||
|
||||
const validatedLoyaltyPage =
|
||||
validateLoyaltyPageSchema.safeParse(loyaltyPage)
|
||||
const validatedLoyaltyPage = loyaltyPageSchema.safeParse(response.data)
|
||||
if (!validatedLoyaltyPage.success) {
|
||||
getLoyaltyPageFailCounter.add(1, {
|
||||
lang,
|
||||
uid,
|
||||
...metricsVariables,
|
||||
error_type: "validation_error",
|
||||
error: JSON.stringify(validatedLoyaltyPage.error),
|
||||
})
|
||||
console.error(
|
||||
"contentstack.loyaltyPage validation error",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
query: metricsVariables,
|
||||
error: validatedLoyaltyPage.error,
|
||||
})
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const loyaltyPage = validatedLoyaltyPage.data.loyalty_page
|
||||
|
||||
const loyaltyTrackingData: TrackingSDKPageData = {
|
||||
pageId: response.data.loyalty_page.system.uid,
|
||||
lang: response.data.loyalty_page.system.locale as Lang,
|
||||
publishedDate: response.data.loyalty_page.system.updated_at,
|
||||
createdDate: response.data.loyalty_page.system.created_at,
|
||||
pageId: loyaltyPage.system.uid,
|
||||
lang: loyaltyPage.system.locale as Lang,
|
||||
publishedDate: loyaltyPage.system.updated_at,
|
||||
createdDate: loyaltyPage.system.created_at,
|
||||
channel: TrackingChannelEnum["scandic-friends"],
|
||||
pageType: "loyaltycontentpage",
|
||||
}
|
||||
getLoyaltyPageSuccessCounter.add(1, { lang, uid })
|
||||
getLoyaltyPageSuccessCounter.add(1, metricsVariables)
|
||||
console.info(
|
||||
"contentstack.loyaltyPage success",
|
||||
JSON.stringify({ query: { lang, uid } })
|
||||
JSON.stringify({ query: metricsVariables })
|
||||
)
|
||||
|
||||
// Assert LoyaltyPage type to get correct typings for RTE fields
|
||||
return {
|
||||
loyaltyPage,
|
||||
|
||||
@@ -1,106 +1,62 @@
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
import { LoyaltyPageEnum } from "@/types/enums/loyaltyPage"
|
||||
import type { System } from "@/types/requests/system"
|
||||
import type { LoyaltyPageRefs } from "@/types/trpc/routers/contentstack/loyaltyPage"
|
||||
|
||||
import { LoyaltyPageRefsDataRaw } from "./output"
|
||||
export function getConnections({ loyalty_page }: LoyaltyPageRefs) {
|
||||
const connections: System["system"][] = [loyalty_page.system]
|
||||
|
||||
import {
|
||||
LoyaltyBlocksTypenameEnum,
|
||||
LoyaltyCardsGridEnum,
|
||||
SidebarTypenameEnum,
|
||||
} from "@/types/components/loyalty/enums"
|
||||
import type { Edges } from "@/types/requests/utils/edges"
|
||||
import type { NodeRefs } from "@/types/requests/utils/refs"
|
||||
|
||||
export function getConnections(refs: LoyaltyPageRefsDataRaw) {
|
||||
const connections: Edges<NodeRefs>[] = []
|
||||
if (refs.loyalty_page.blocks) {
|
||||
refs.loyalty_page.blocks.forEach((item) => {
|
||||
switch (item.__typename) {
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent: {
|
||||
if (item.content.content.embedded_itemsConnection.edges.length) {
|
||||
connections.push(item.content.content.embedded_itemsConnection)
|
||||
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 LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid: {
|
||||
connections.push(item.cards_grid.cardConnection)
|
||||
item.cards_grid.cardConnection.edges.forEach((card) => {
|
||||
switch (card.node.__typename) {
|
||||
case LoyaltyCardsGridEnum.LoyaltyCard: {
|
||||
if (card.node.link) {
|
||||
connections.push(card.node.link?.linkConnection)
|
||||
}
|
||||
break
|
||||
}
|
||||
case LoyaltyCardsGridEnum.Card: {
|
||||
if (card.node.primary_button) {
|
||||
connections.push(card.node.primary_button?.linkConnection)
|
||||
} else if (card.node.secondary_button) {
|
||||
connections.push(card.node.secondary_button?.linkConnection)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksShortcuts: {
|
||||
item.shortcuts.shortcuts.forEach((shortcut) => {
|
||||
if (shortcut.linkConnection.edges.length) {
|
||||
connections.push(shortcut.linkConnection)
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent: {
|
||||
if (item.dynamic_content.link.pageConnection.edges.length) {
|
||||
connections.push(item.dynamic_content.link.pageConnection)
|
||||
case LoyaltyPageEnum.ContentStack.blocks.Content:
|
||||
if (block.content.length) {
|
||||
// TS has trouble infering the filtered types
|
||||
// @ts-ignore
|
||||
connections.push(...block.content)
|
||||
}
|
||||
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)
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
if (refs.loyalty_page.sidebar) {
|
||||
refs.loyalty_page.sidebar?.forEach((item) => {
|
||||
switch (item.__typename) {
|
||||
case SidebarTypenameEnum.LoyaltyPageSidebarContent:
|
||||
if (item.content.content.embedded_itemsConnection.edges.length) {
|
||||
connections.push(item.content.content.embedded_itemsConnection)
|
||||
|
||||
if (loyalty_page.sidebar) {
|
||||
loyalty_page.sidebar.forEach((block) => {
|
||||
switch (block?.__typename) {
|
||||
case LoyaltyPageEnum.ContentStack.sidebar.Content:
|
||||
if (block.content.length) {
|
||||
// TS has trouble infering the filtered types
|
||||
// @ts-ignore
|
||||
connections.push(...block.content)
|
||||
}
|
||||
break
|
||||
case SidebarTypenameEnum.LoyaltyPageSidebarJoinLoyaltyContact:
|
||||
if (item.join_loyalty_contact.button?.linkConnection) {
|
||||
connections.push(item.join_loyalty_contact.button.linkConnection)
|
||||
case LoyaltyPageEnum.ContentStack.sidebar.JoinLoyaltyContact:
|
||||
if (block.join_loyalty_contact?.button) {
|
||||
connections.push(block.join_loyalty_contact.button)
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
export function makeButtonObject(button: any) {
|
||||
if (!button) return null
|
||||
|
||||
const isContenstackLink =
|
||||
button?.is_contentstack_link || button.linkConnection?.edges?.length
|
||||
const linkConnnectionNode = isContenstackLink
|
||||
? button.linkConnection.edges[0]?.node
|
||||
: null
|
||||
|
||||
return {
|
||||
openInNewTab: button?.open_in_new_tab,
|
||||
title:
|
||||
button.cta_text ||
|
||||
(linkConnnectionNode
|
||||
? linkConnnectionNode.title
|
||||
: button.external_link.title),
|
||||
href: linkConnnectionNode
|
||||
? linkConnnectionNode.web?.original_url ||
|
||||
removeMultipleSlashes(
|
||||
`/${linkConnnectionNode.system.locale}/${linkConnnectionNode.url}`
|
||||
)
|
||||
: button.external_link.href,
|
||||
isExternal: !isContenstackLink,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,11 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const getMetaDataSchema = z.object({
|
||||
breadcrumbsTitle: z.string().optional(),
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
imageConnection: z
|
||||
.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
import { page } from "../schemas/metadata"
|
||||
|
||||
const page = z.object({
|
||||
web: z.object({
|
||||
seo_metadata: z.object({
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
imageConnection: z
|
||||
.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
breadcrumbs: z.object({
|
||||
title: z.string(),
|
||||
}),
|
||||
}),
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
export type Page = z.infer<typeof page>
|
||||
|
||||
export const validateMyPagesMetaDataContentstackSchema = z.object({
|
||||
account_page: page,
|
||||
})
|
||||
|
||||
export type GetMyPagesMetaDataData = z.infer<
|
||||
typeof validateMyPagesMetaDataContentstackSchema
|
||||
>
|
||||
|
||||
export const validateLoyaltyPageMetaDataContentstackSchema = z.object({
|
||||
export const getLoyaltyPageMetadataSchema = z.object({
|
||||
loyalty_page: page,
|
||||
})
|
||||
|
||||
export type GetLoyaltyPageMetaDataData = z.infer<
|
||||
typeof validateLoyaltyPageMetaDataContentstackSchema
|
||||
typeof getLoyaltyPageMetadataSchema
|
||||
>
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { GetLoyaltyPageMetaData } from "@/lib/graphql/Query/MetaDataLoyaltyPage.graphql"
|
||||
import { GetMyPagesMetaData } from "@/lib/graphql/Query/MetaDataMyPages.graphql"
|
||||
import { GetLoyaltyPageMetaData } from "@/lib/graphql/Query/LoyaltyPage/MetaData.graphql"
|
||||
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
|
||||
import {
|
||||
type GetLoyaltyPageMetaDataData,
|
||||
type GetMyPagesMetaDataData,
|
||||
validateLoyaltyPageMetaDataContentstackSchema,
|
||||
validateMyPagesMetaDataContentstackSchema,
|
||||
getLoyaltyPageMetadataSchema,
|
||||
} from "./output"
|
||||
import { getMetaData, getResponse, type Variables } from "./utils"
|
||||
|
||||
@@ -18,38 +15,19 @@ async function getLoyaltyPageMetaData(variables: Variables) {
|
||||
variables
|
||||
)
|
||||
|
||||
const validatedMetaDataData =
|
||||
validateLoyaltyPageMetaDataContentstackSchema.safeParse(response.data)
|
||||
const validatedMetadata = getLoyaltyPageMetadataSchema.safeParse(
|
||||
response.data
|
||||
)
|
||||
|
||||
if (!validatedMetaDataData.success) {
|
||||
if (!validatedMetadata.success) {
|
||||
console.error(
|
||||
`Failed to validate Loyaltypage MetaData Data - (uid: ${variables.uid})`
|
||||
)
|
||||
console.error(validatedMetaDataData.error)
|
||||
console.error(validatedMetadata.error)
|
||||
return null
|
||||
}
|
||||
|
||||
return getMetaData(validatedMetaDataData.data.loyalty_page)
|
||||
}
|
||||
|
||||
async function getMyPagesMetaData(variables: Variables) {
|
||||
const response = await getResponse<GetMyPagesMetaDataData>(
|
||||
GetMyPagesMetaData,
|
||||
variables
|
||||
)
|
||||
|
||||
const validatedMetaDataData =
|
||||
validateMyPagesMetaDataContentstackSchema.safeParse(response.data)
|
||||
|
||||
if (!validatedMetaDataData.success) {
|
||||
console.error(
|
||||
`Failed to validate My Page MetaData Data - (uid: ${variables.uid})`
|
||||
)
|
||||
console.error(validatedMetaDataData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
return getMetaData(validatedMetaDataData.data.account_page)
|
||||
return getMetaData(validatedMetadata.data.loyalty_page)
|
||||
}
|
||||
|
||||
export const metaDataQueryRouter = router({
|
||||
@@ -60,8 +38,6 @@ export const metaDataQueryRouter = router({
|
||||
}
|
||||
|
||||
switch (ctx.contentType) {
|
||||
case PageTypeEnum.accountPage:
|
||||
return await getMyPagesMetaData(variables)
|
||||
case PageTypeEnum.loyaltyPage:
|
||||
return await getLoyaltyPageMetaData(variables)
|
||||
default:
|
||||
|
||||
@@ -4,7 +4,7 @@ import { internalServerError, notFound } from "@/server/errors/trpc"
|
||||
|
||||
import { generateTag } from "@/utils/generateTag"
|
||||
|
||||
import { getMetaDataSchema, Page } from "./output"
|
||||
import { getMetaDataSchema, Page } from "../schemas/metadata"
|
||||
|
||||
export type Variables = {
|
||||
locale: Lang
|
||||
|
||||
@@ -1,49 +1,17 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
import { PageLinkEnum } from "@/types/requests/pageLinks"
|
||||
|
||||
const node = z.object({
|
||||
system: z.object({
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
}),
|
||||
title: z.string(),
|
||||
url: z.string(),
|
||||
})
|
||||
|
||||
const web = z.object({
|
||||
original_url: z.string().optional(),
|
||||
})
|
||||
|
||||
const accountPageLink = z
|
||||
.object({
|
||||
__typename: z.literal(PageLinkEnum.AccountPage),
|
||||
})
|
||||
.merge(node)
|
||||
|
||||
const contentPageLink = z
|
||||
.object({
|
||||
__typename: z.literal(PageLinkEnum.ContentPage),
|
||||
web,
|
||||
})
|
||||
.merge(node)
|
||||
|
||||
const loyaltyPageLink = z
|
||||
.object({
|
||||
__typename: z.literal(PageLinkEnum.LoyaltyPage),
|
||||
web,
|
||||
})
|
||||
.merge(node)
|
||||
import { systemSchema } from "../../schemas/system"
|
||||
|
||||
const pageConnection = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
accountPageLink,
|
||||
contentPageLink,
|
||||
loyaltyPageLink,
|
||||
pageLinks.accountPageSchema,
|
||||
pageLinks.contentPageSchema,
|
||||
pageLinks.loyaltyPageSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
@@ -52,13 +20,11 @@ const pageConnection = z.object({
|
||||
const pageConnectionRefs = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
__typename: z.nativeEnum(PageLinkEnum),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageRefSchema,
|
||||
pageLinks.contentPageRefSchema,
|
||||
pageLinks.loyaltyPageRefSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
})
|
||||
@@ -76,10 +42,7 @@ export const navigationRefsPayloadSchema = z.object({
|
||||
),
|
||||
})
|
||||
),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
|
||||
@@ -3,7 +3,7 @@ import { metrics } from "@opentelemetry/api"
|
||||
import {
|
||||
GetNavigationMyPages,
|
||||
GetNavigationMyPagesRefs,
|
||||
} from "@/lib/graphql/Query/NavigationMyPages.graphql"
|
||||
} from "@/lib/graphql/Query/AccountPage/Navigation.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { notFound } from "@/server/errors/trpc"
|
||||
import { contentstackBaseProcedure, router } from "@/server/trpc"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import { PageLinkEnum } from "@/types/requests/pageLinks"
|
||||
import { ContentEnum } from "@/types/enums/content"
|
||||
import type { Edges } from "@/types/requests/utils/edges"
|
||||
import type { NodeRefs } from "@/types/requests/utils/refs"
|
||||
import type { GetNavigationMyPagesRefsData, MenuItems } from "./output"
|
||||
@@ -32,8 +32,8 @@ export function mapMenuItems(menuItems: MenuItems) {
|
||||
const page = link.page.edges[0].node
|
||||
let originalUrl = undefined
|
||||
if (
|
||||
page.__typename === PageLinkEnum.ContentPage ||
|
||||
page.__typename === PageLinkEnum.LoyaltyPage
|
||||
page.__typename === ContentEnum.blocks.ContentPage ||
|
||||
page.__typename === ContentEnum.blocks.LoyaltyPage
|
||||
) {
|
||||
if (page.web.original_url) {
|
||||
originalUrl = page.web.original_url
|
||||
|
||||
59
server/routers/contentstack/schemas/blocks/activitiesCard.ts
Normal file
59
server/routers/contentstack/schemas/blocks/activitiesCard.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import { tempImageVaultAssetSchema } from "../imageVault"
|
||||
|
||||
import { HotelPageEnum } from "@/types/enums/hotelPage"
|
||||
|
||||
export const activitiesCard = z.object({
|
||||
typename: z
|
||||
.literal(HotelPageEnum.ContentStack.blocks.ActivitiesCard)
|
||||
.optional()
|
||||
.default(HotelPageEnum.ContentStack.blocks.ActivitiesCard),
|
||||
upcoming_activities_card: z
|
||||
.object({
|
||||
background_image: tempImageVaultAssetSchema,
|
||||
body_text: z.string(),
|
||||
cta_text: z.string(),
|
||||
heading: z.string(),
|
||||
open_in_new_tab: z.boolean(),
|
||||
scripted_title: z.string().optional(),
|
||||
hotel_page_activities_content_pageConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
pageLinks.contentPageSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
let contentPage = { href: "" }
|
||||
if (data.hotel_page_activities_content_pageConnection.edges.length) {
|
||||
const page =
|
||||
data.hotel_page_activities_content_pageConnection.edges[0].node
|
||||
if (page.web.original_url) {
|
||||
contentPage = {
|
||||
href: page.web.original_url,
|
||||
}
|
||||
} else {
|
||||
contentPage = {
|
||||
href: removeMultipleSlashes(`/${page.system.locale}/${page.url}`),
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
background_image: data.background_image,
|
||||
body_text: data.body_text,
|
||||
contentPage,
|
||||
cta_text: data.cta_text,
|
||||
heading: data.heading,
|
||||
open_in_new_tab: !!data.open_in_new_tab,
|
||||
scripted_title: data.scripted_title,
|
||||
}
|
||||
}),
|
||||
})
|
||||
162
server/routers/contentstack/schemas/blocks/cardsGrid.ts
Normal file
162
server/routers/contentstack/schemas/blocks/cardsGrid.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { tempImageVaultAssetSchema } from "../imageVault"
|
||||
import { systemSchema } from "../system"
|
||||
import { buttonSchema } from "./utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "./utils/linkConnection"
|
||||
|
||||
import { BlocksEnums } from "@/types/enums/blocks"
|
||||
import { CardsGridEnum } from "@/types/enums/cardsGrid"
|
||||
|
||||
const cardBlockSchema = z.object({
|
||||
__typename: z.literal(CardsGridEnum.cards.Card),
|
||||
// JSON - ImageVault Image
|
||||
background_image: tempImageVaultAssetSchema,
|
||||
body_text: z.string().optional().default(""),
|
||||
has_primary_button: z.boolean().default(false),
|
||||
has_secondary_button: z.boolean().default(false),
|
||||
has_sidepeek_button: z.boolean().optional().default(false),
|
||||
heading: z.string().optional().default(""),
|
||||
is_content_card: z.boolean().optional().default(false),
|
||||
primary_button: buttonSchema,
|
||||
scripted_top_title: z.string().optional(),
|
||||
secondary_button: buttonSchema,
|
||||
sidepeek_button: z
|
||||
.object({
|
||||
call_to_action_text: z.string().optional(),
|
||||
})
|
||||
.optional(),
|
||||
system: systemSchema,
|
||||
title: z.string().optional(),
|
||||
})
|
||||
|
||||
const loyaltyCardBlockSchema = z.object({
|
||||
__typename: z.literal(CardsGridEnum.cards.LoyaltyCard),
|
||||
body_text: z.string().optional(),
|
||||
heading: z.string().optional().default(""),
|
||||
// JSON - ImageVault Image
|
||||
image: tempImageVaultAssetSchema,
|
||||
link: buttonSchema,
|
||||
system: systemSchema,
|
||||
title: z.string().optional(),
|
||||
})
|
||||
|
||||
export const cardsGridSchema = z.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.CardsGrid)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.CardsGrid),
|
||||
cards_grid: z
|
||||
.object({
|
||||
cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
cardBlockSchema,
|
||||
loyaltyCardBlockSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
layout: z.enum(["twoColumnGrid", "threeColumnGrid", "twoPlusOne"]),
|
||||
preamble: z.string().optional().default(""),
|
||||
theme: z.enum(["one", "two", "three"]).nullable(),
|
||||
title: z.string().optional().default(""),
|
||||
})
|
||||
.transform((data) => {
|
||||
return {
|
||||
layout: data.layout,
|
||||
preamble: data.preamble,
|
||||
theme: data.theme,
|
||||
title: data.title,
|
||||
cards: data.cardConnection.edges.map((card) => {
|
||||
if (card.node.__typename === CardsGridEnum.cards.Card) {
|
||||
return {
|
||||
__typename: card.node.__typename,
|
||||
backgroundImage: card.node.background_image,
|
||||
body_text: card.node.body_text,
|
||||
heading: card.node.heading,
|
||||
isContentCard: card.node.is_content_card,
|
||||
primaryButton: card.node.has_primary_button
|
||||
? card.node.primary_button
|
||||
: undefined,
|
||||
scripted_top_title: card.node.scripted_top_title,
|
||||
secondaryButton: card.node.has_secondary_button
|
||||
? card.node.secondary_button
|
||||
: undefined,
|
||||
sidePeekButton:
|
||||
card.node.has_sidepeek_button &&
|
||||
card.node.sidepeek_button?.call_to_action_text
|
||||
? {
|
||||
title: card.node.sidepeek_button.call_to_action_text,
|
||||
}
|
||||
: undefined,
|
||||
system: card.node.system,
|
||||
title: card.node.title,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
__typename: card.node.__typename,
|
||||
body_text: card.node.body_text,
|
||||
heading: card.node.heading,
|
||||
image: card.node.image,
|
||||
link: card.node.link,
|
||||
system: card.node.system,
|
||||
title: card.node.title,
|
||||
}
|
||||
}
|
||||
}),
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
const cardBlockRefsSchema = z.object({
|
||||
__typename: z.literal(CardsGridEnum.cards.Card),
|
||||
primary_button: linkConnectionRefsSchema,
|
||||
secondary_button: linkConnectionRefsSchema,
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
const loyaltyCardBlockRefsSchema = z.object({
|
||||
__typename: z.literal(CardsGridEnum.cards.LoyaltyCard),
|
||||
link: linkConnectionRefsSchema,
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export const cardGridRefsSchema = z.object({
|
||||
cards_grid: z
|
||||
.object({
|
||||
cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
cardBlockRefsSchema,
|
||||
loyaltyCardBlockRefsSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data.cardConnection.edges
|
||||
.map(({ node }) => {
|
||||
if (node.__typename === CardsGridEnum.cards.Card) {
|
||||
const cards = [node.system]
|
||||
if (node.primary_button) {
|
||||
cards.push(node.primary_button)
|
||||
}
|
||||
if (node.secondary_button) {
|
||||
cards.push(node.secondary_button)
|
||||
}
|
||||
return cards
|
||||
} else {
|
||||
const loyaltyCards = [node.system]
|
||||
if (node.link) {
|
||||
loyaltyCards.push(node.link)
|
||||
}
|
||||
return loyaltyCards
|
||||
}
|
||||
})
|
||||
.flat()
|
||||
}),
|
||||
})
|
||||
83
server/routers/contentstack/schemas/blocks/content.ts
Normal file
83
server/routers/contentstack/schemas/blocks/content.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
import { imageRefsSchema, imageSchema } from "./image"
|
||||
import {
|
||||
imageContainerRefsSchema,
|
||||
imageContainerSchema,
|
||||
} from "./imageContainer"
|
||||
|
||||
import { BlocksEnums } from "@/types/enums/blocks"
|
||||
import { ContentEnum } from "@/types/enums/content"
|
||||
|
||||
export const contentSchema = z.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.Content)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.Content),
|
||||
content: z
|
||||
.object({
|
||||
content: z.object({
|
||||
json: z.any(), // JSON
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z
|
||||
.discriminatedUnion("__typename", [
|
||||
imageContainerSchema,
|
||||
imageSchema,
|
||||
pageLinks.accountPageSchema,
|
||||
pageLinks.contentPageSchema,
|
||||
pageLinks.hotelPageSchema,
|
||||
pageLinks.loyaltyPageSchema,
|
||||
])
|
||||
.transform((data) => {
|
||||
const link = pageLinks.transform(data)
|
||||
if (link) {
|
||||
return link
|
||||
}
|
||||
return data
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
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", [
|
||||
imageRefsSchema,
|
||||
imageContainerRefsSchema,
|
||||
pageLinks.accountPageRefSchema,
|
||||
pageLinks.contentPageRefSchema,
|
||||
pageLinks.hotelPageRefSchema,
|
||||
pageLinks.loyaltyPageRefSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data.content.embedded_itemsConnection.edges
|
||||
.filter(({ node }) => node.__typename !== ContentEnum.blocks.SysAsset)
|
||||
.map(({ node }) => {
|
||||
if ("system" in node) {
|
||||
return node.system
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter((node) => !!node)
|
||||
}),
|
||||
})
|
||||
23
server/routers/contentstack/schemas/blocks/contentEmbeds.ts
Normal file
23
server/routers/contentstack/schemas/blocks/contentEmbeds.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
import { imageSchema } from "./image"
|
||||
import { imageContainerSchema } from "./imageContainer"
|
||||
|
||||
export const contentEmbedsSchema = z
|
||||
.discriminatedUnion("__typename", [
|
||||
imageContainerSchema,
|
||||
imageSchema,
|
||||
pageLinks.accountPageSchema,
|
||||
pageLinks.contentPageSchema,
|
||||
pageLinks.hotelPageSchema,
|
||||
pageLinks.loyaltyPageSchema,
|
||||
])
|
||||
.transform((data) => {
|
||||
const link = pageLinks.transform(data)
|
||||
if (link) {
|
||||
return link
|
||||
}
|
||||
return data
|
||||
})
|
||||
79
server/routers/contentstack/schemas/blocks/dynamicContent.ts
Normal file
79
server/routers/contentstack/schemas/blocks/dynamicContent.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
import { BlocksEnums } from "@/types/enums/blocks"
|
||||
import { DynamicContentEnum } from "@/types/enums/dynamicContent"
|
||||
|
||||
export const dynamicContentSchema = z.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.DynamicContent)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.DynamicContent),
|
||||
dynamic_content: z.object({
|
||||
component: z.enum(DynamicContentEnum.Blocks.enums),
|
||||
subtitle: z.string().optional().default(""),
|
||||
title: z.string().optional().default(""),
|
||||
link: z
|
||||
.object({
|
||||
text: z.string().optional().default(""),
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z
|
||||
.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageSchema,
|
||||
pageLinks.contentPageSchema,
|
||||
pageLinks.hotelPageSchema,
|
||||
pageLinks.loyaltyPageSchema,
|
||||
])
|
||||
.transform((data) => {
|
||||
const link = pageLinks.transform(data)
|
||||
if (link) {
|
||||
return link
|
||||
}
|
||||
return data
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (data.linkConnection?.edges.length) {
|
||||
const link = data.linkConnection.edges?.[0]?.node
|
||||
return {
|
||||
href: link.url,
|
||||
text: data.text,
|
||||
title: link.title,
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const dynamicContentRefsSchema = z.object({
|
||||
dynamic_content: z.object({
|
||||
link: z
|
||||
.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageRefSchema,
|
||||
pageLinks.contentPageRefSchema,
|
||||
pageLinks.hotelPageRefSchema,
|
||||
pageLinks.loyaltyPageRefSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (data.linkConnection?.edges.length) {
|
||||
return data.linkConnection.edges[0].node.system
|
||||
}
|
||||
return null
|
||||
}),
|
||||
}),
|
||||
})
|
||||
27
server/routers/contentstack/schemas/blocks/image.ts
Normal file
27
server/routers/contentstack/schemas/blocks/image.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { ContentEnum } from "@/types/enums/content"
|
||||
|
||||
export const imageSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.SysAsset),
|
||||
description: z.string().optional(),
|
||||
dimension: z.object({
|
||||
height: z.number(),
|
||||
width: z.number(),
|
||||
}),
|
||||
metadata: z.any(), // JSON
|
||||
// system for SysAssets is not the same type
|
||||
// as for all other types eventhough they have
|
||||
// the exact same structure, that's why systemSchema
|
||||
// is not used as that correlates to the
|
||||
// EntrySystemField type
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
}),
|
||||
title: z.string().optional(),
|
||||
url: z.string().optional(),
|
||||
})
|
||||
|
||||
export const imageRefsSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.SysAsset),
|
||||
})
|
||||
21
server/routers/contentstack/schemas/blocks/imageContainer.ts
Normal file
21
server/routers/contentstack/schemas/blocks/imageContainer.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { tempImageVaultAssetSchema } from "../imageVault"
|
||||
import { systemSchema } from "../system"
|
||||
|
||||
import { ContentEnum } from "@/types/enums/content"
|
||||
|
||||
export const imageContainerSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.ImageContainer),
|
||||
// JSON - ImageVault Image
|
||||
image_left: tempImageVaultAssetSchema,
|
||||
// JSON - ImageVault Image
|
||||
image_right: tempImageVaultAssetSchema,
|
||||
system: systemSchema,
|
||||
title: z.string().optional(),
|
||||
})
|
||||
|
||||
export const imageContainerRefsSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.ImageContainer),
|
||||
system: systemSchema,
|
||||
})
|
||||
83
server/routers/contentstack/schemas/blocks/shortcuts.ts
Normal file
83
server/routers/contentstack/schemas/blocks/shortcuts.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
import { BlocksEnums } from "@/types/enums/blocks"
|
||||
|
||||
export const shortcutsSchema = z.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.Shortcuts)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.Shortcuts),
|
||||
shortcuts: z.object({
|
||||
subtitle: z.string().nullable(),
|
||||
title: z.string().nullable(),
|
||||
shortcuts: z
|
||||
.array(
|
||||
z.object({
|
||||
open_in_new_tab: z.boolean(),
|
||||
text: z.string().optional().default(""),
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z
|
||||
.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageSchema,
|
||||
pageLinks.contentPageSchema,
|
||||
pageLinks.loyaltyPageSchema,
|
||||
])
|
||||
.transform((data) => {
|
||||
const link = pageLinks.transform(data)
|
||||
if (link) {
|
||||
return link
|
||||
}
|
||||
return data
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.transform((data) => {
|
||||
return data
|
||||
.filter((node) => node.linkConnection.edges.length)
|
||||
.map((node) => {
|
||||
const link = node.linkConnection.edges[0].node
|
||||
return {
|
||||
openInNewTab: node.open_in_new_tab,
|
||||
text: node.text,
|
||||
title: link.title,
|
||||
url: link.url,
|
||||
}
|
||||
})
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const shortcutsRefsSchema = z.object({
|
||||
shortcuts: z.object({
|
||||
shortcuts: z
|
||||
.array(
|
||||
z.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageRefSchema,
|
||||
pageLinks.contentPageRefSchema,
|
||||
pageLinks.loyaltyPageRefSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.transform((data) =>
|
||||
data
|
||||
.map((shortcut) => {
|
||||
return shortcut.linkConnection.edges.map(({ node }) => node.system)
|
||||
})
|
||||
.flat()
|
||||
),
|
||||
}),
|
||||
})
|
||||
84
server/routers/contentstack/schemas/blocks/textCols.ts
Normal file
84
server/routers/contentstack/schemas/blocks/textCols.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
import { imageRefsSchema, imageSchema } from "./image"
|
||||
|
||||
import { BlocksEnums } from "@/types/enums/blocks"
|
||||
import { ContentEnum } from "@/types/enums/content"
|
||||
|
||||
export const textColsSchema = z
|
||||
.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.TextCols)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.TextCols),
|
||||
text_cols: z.object({
|
||||
columns: z.array(
|
||||
z.object({
|
||||
title: z.string().optional().default(""),
|
||||
text: z.object({
|
||||
json: z.any(), // JSON
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
imageSchema,
|
||||
pageLinks.contentPageSchema,
|
||||
pageLinks.hotelPageSchema,
|
||||
pageLinks.loyaltyPageSchema,
|
||||
])
|
||||
.transform((data) => {
|
||||
const link = pageLinks.transform(data)
|
||||
if (link) {
|
||||
return link
|
||||
}
|
||||
return data
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
const actualRefs = z.discriminatedUnion("__typename", [
|
||||
pageLinks.contentPageRefSchema,
|
||||
pageLinks.hotelPageRefSchema,
|
||||
pageLinks.loyaltyPageRefSchema,
|
||||
])
|
||||
|
||||
type Refs = {
|
||||
node: z.TypeOf<typeof actualRefs>
|
||||
}
|
||||
|
||||
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", [
|
||||
imageRefsSchema,
|
||||
...actualRefs.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()
|
||||
}),
|
||||
})
|
||||
25
server/routers/contentstack/schemas/blocks/textContent.ts
Normal file
25
server/routers/contentstack/schemas/blocks/textContent.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { imageSchema } from "./image"
|
||||
|
||||
import { BlocksEnums } from "@/types/enums/blocks"
|
||||
|
||||
export const textContentSchema = z.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.TextContent)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.TextContent),
|
||||
text_content: z.object({
|
||||
content: z.object({
|
||||
json: z.any(),
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [imageSchema]),
|
||||
})
|
||||
),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
@@ -0,0 +1,54 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
export const buttonSchema = z
|
||||
.object({
|
||||
cta_text: z.string().optional().default(""),
|
||||
open_in_new_tab: z.boolean().default(false),
|
||||
external_link: z
|
||||
.object({
|
||||
href: z.string().optional().default(""),
|
||||
title: z.string().optional(),
|
||||
})
|
||||
.optional(),
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z
|
||||
.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageSchema,
|
||||
pageLinks.contentPageSchema,
|
||||
pageLinks.loyaltyPageSchema,
|
||||
])
|
||||
.transform((data) => {
|
||||
const link = pageLinks.transform(data)
|
||||
if (link) {
|
||||
return link
|
||||
}
|
||||
return data
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (data.linkConnection?.edges?.length) {
|
||||
const link = data.linkConnection.edges[0].node
|
||||
return {
|
||||
href: link.url,
|
||||
isExternal: false,
|
||||
openInNewTab: data.open_in_new_tab,
|
||||
title: data.cta_text ? data.cta_text : link.title,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
href: data.external_link?.href ?? "",
|
||||
isExternal: true,
|
||||
openInNewTab: data.open_in_new_tab,
|
||||
title: data.external_link?.title
|
||||
? data.external_link?.title
|
||||
: data.cta_text,
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,25 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
export const linkConnectionRefsSchema = z
|
||||
.object({
|
||||
linkConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageRefSchema,
|
||||
pageLinks.contentPageRefSchema,
|
||||
pageLinks.loyaltyPageRefSchema,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (!data.linkConnection.edges.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return data.linkConnection.edges[0].node.system
|
||||
})
|
||||
@@ -1,5 +1,7 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { makeImageVaultImage } from "@/utils/imageVault"
|
||||
|
||||
const metaData = z.object({
|
||||
DefinitionType: z.number().nullable().optional(),
|
||||
Description: z.string().nullable(),
|
||||
@@ -120,3 +122,21 @@ export const imageVaultAssetTransformedSchema = imageVaultAssetSchema.transform(
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export const tempImageVaultAssetSchema = imageVaultAssetSchema
|
||||
.optional()
|
||||
.or(
|
||||
// Temp since there is a bug in Contentstack
|
||||
// sending empty objects when there has been an
|
||||
// image selected previously but has since been
|
||||
// deleted
|
||||
z.object({})
|
||||
)
|
||||
.transform((data) => {
|
||||
if (data) {
|
||||
if ("Name" in data) {
|
||||
return makeImageVaultImage(data)
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
|
||||
46
server/routers/contentstack/schemas/metadata.ts
Normal file
46
server/routers/contentstack/schemas/metadata.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { systemSchema } from "./system"
|
||||
|
||||
export const getMetaDataSchema = z.object({
|
||||
breadcrumbsTitle: z.string().optional(),
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
imageConnection: z
|
||||
.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
|
||||
export const page = z.object({
|
||||
web: z.object({
|
||||
seo_metadata: z.object({
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
imageConnection: z
|
||||
.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
url: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
breadcrumbs: z.object({
|
||||
title: z.string(),
|
||||
}),
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export type Page = z.infer<typeof page>
|
||||
120
server/routers/contentstack/schemas/pageLinks.ts
Normal file
120
server/routers/contentstack/schemas/pageLinks.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import { systemSchema } from "./system"
|
||||
|
||||
import { ContentEnum } from "@/types/enums/content"
|
||||
|
||||
export const pageLinkSchema = z.object({
|
||||
system: systemSchema,
|
||||
title: z.string().optional().default(""),
|
||||
url: z.string().optional().default(""),
|
||||
})
|
||||
|
||||
export const accountPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.AccountPage),
|
||||
})
|
||||
.merge(pageLinkSchema)
|
||||
|
||||
export const accountPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.AccountPage),
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
export const extendedPageLinkSchema = pageLinkSchema.merge(
|
||||
z.object({
|
||||
web: z.object({
|
||||
original_url: z.string().optional().default(""),
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
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,
|
||||
})
|
||||
|
||||
export const hotelPageSchema = z
|
||||
.object({
|
||||
__typename: z.literal(ContentEnum.blocks.HotelPage),
|
||||
})
|
||||
.merge(extendedPageLinkSchema)
|
||||
|
||||
export const hotelPageRefSchema = z.object({
|
||||
__typename: z.literal(ContentEnum.blocks.HotelPage),
|
||||
system: systemSchema,
|
||||
})
|
||||
|
||||
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,
|
||||
})
|
||||
|
||||
type Data =
|
||||
| z.output<typeof accountPageSchema>
|
||||
| z.output<typeof contentPageSchema>
|
||||
| z.output<typeof hotelPageSchema>
|
||||
| z.output<typeof loyaltyPageSchema>
|
||||
| Object
|
||||
|
||||
export function transform(data: Data) {
|
||||
if (data && "__typename" in data) {
|
||||
switch (data.__typename) {
|
||||
case ContentEnum.blocks.AccountPage:
|
||||
case ContentEnum.blocks.HotelPage:
|
||||
return {
|
||||
__typename: data.__typename,
|
||||
system: data.system,
|
||||
title: data.title,
|
||||
url: removeMultipleSlashes(`/${data.system.locale}/${data.url}`),
|
||||
}
|
||||
case ContentEnum.blocks.ContentPage:
|
||||
case ContentEnum.blocks.LoyaltyPage:
|
||||
// TODO: Once all links use this transform
|
||||
// `web` can be removed and not to be worried
|
||||
// about throughout the application
|
||||
return {
|
||||
__typename: data.__typename,
|
||||
system: data.system,
|
||||
title: data.title,
|
||||
url: data.web.original_url
|
||||
? removeMultipleSlashes(data.web.original_url)
|
||||
: removeMultipleSlashes(`/${data.system.locale}/${data.url}`),
|
||||
web: data.web,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type RefData =
|
||||
| z.output<typeof accountPageRefSchema>
|
||||
| z.output<typeof contentPageRefSchema>
|
||||
| z.output<typeof hotelPageRefSchema>
|
||||
| z.output<typeof loyaltyPageRefSchema>
|
||||
| Object
|
||||
|
||||
export function transformRef(data: RefData) {
|
||||
if (data && "__typename" in data) {
|
||||
switch (data.__typename) {
|
||||
case ContentEnum.blocks.AccountPage:
|
||||
case ContentEnum.blocks.ContentPage:
|
||||
case ContentEnum.blocks.HotelPage:
|
||||
case ContentEnum.blocks.LoyaltyPage:
|
||||
return data.system
|
||||
}
|
||||
}
|
||||
}
|
||||
87
server/routers/contentstack/schemas/sidebar/content.ts
Normal file
87
server/routers/contentstack/schemas/sidebar/content.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
import { imageRefsSchema, imageSchema } from "../blocks/image"
|
||||
import {
|
||||
imageContainerRefsSchema,
|
||||
imageContainerSchema,
|
||||
} from "../blocks/imageContainer"
|
||||
|
||||
import { ContentEnum } from "@/types/enums/content"
|
||||
import { SidebarEnums } from "@/types/enums/sidebar"
|
||||
import { System } from "@/types/requests/system"
|
||||
|
||||
export const contentSchema = z.object({
|
||||
typename: z
|
||||
.literal(SidebarEnums.blocks.Content)
|
||||
.optional()
|
||||
.default(SidebarEnums.blocks.Content),
|
||||
content: z
|
||||
.object({
|
||||
content: z.object({
|
||||
json: z.any(), // JSON
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z
|
||||
.discriminatedUnion("__typename", [
|
||||
imageContainerSchema,
|
||||
imageSchema,
|
||||
pageLinks.contentPageSchema,
|
||||
pageLinks.loyaltyPageSchema,
|
||||
])
|
||||
.transform((data) => {
|
||||
const link = pageLinks.transform(data)
|
||||
if (link) {
|
||||
return link
|
||||
}
|
||||
return data
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
return {
|
||||
embedded_itemsConnection: data.content.embedded_itemsConnection,
|
||||
json: data.content.json,
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
const actualRefs = z.discriminatedUnion("__typename", [
|
||||
imageContainerRefsSchema,
|
||||
pageLinks.contentPageRefSchema,
|
||||
pageLinks.loyaltyPageRefSchema,
|
||||
])
|
||||
|
||||
type Ref = typeof actualRefs._type
|
||||
type Refs = {
|
||||
node: Ref
|
||||
}
|
||||
|
||||
export const contentRefsSchema = z.object({
|
||||
content: z
|
||||
.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.discriminatedUnion("__typename", [
|
||||
imageRefsSchema,
|
||||
...actualRefs.options,
|
||||
]),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
const filtered = data.content.embedded_itemsConnection.edges.filter(
|
||||
(block) => block.node.__typename !== ContentEnum.blocks.SysAsset
|
||||
) as unknown as Refs[] // TS issues with filtered arrays
|
||||
return filtered.map((block) => block.node.system)
|
||||
}),
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { DynamicContentEnum } from "@/types/enums/dynamicContent"
|
||||
import { SidebarEnums } from "@/types/enums/sidebar"
|
||||
|
||||
export const dynamicContentSchema = z.object({
|
||||
typename: z
|
||||
.literal(SidebarEnums.blocks.DynamicContent)
|
||||
.optional()
|
||||
.default(SidebarEnums.blocks.DynamicContent),
|
||||
dynamic_content: z.object({
|
||||
component: z.enum(DynamicContentEnum.Sidebar.enums),
|
||||
}),
|
||||
})
|
||||
@@ -0,0 +1,58 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { buttonSchema } from "../blocks/utils/buttonLinkSchema"
|
||||
import { linkConnectionRefsSchema } from "../blocks/utils/linkConnection"
|
||||
|
||||
import { JoinLoyaltyContactEnums } from "@/types/enums/joinLoyaltyContact"
|
||||
import { SidebarEnums } from "@/types/enums/sidebar"
|
||||
|
||||
export const contactSchema = z.object({
|
||||
contact: z.array(
|
||||
z
|
||||
.object({
|
||||
__typename: z
|
||||
.literal(JoinLoyaltyContactEnums.ContentStack.contact.ContentPage)
|
||||
.or(
|
||||
z.literal(JoinLoyaltyContactEnums.ContentStack.contact.LoyaltyPage)
|
||||
),
|
||||
typename: z
|
||||
.literal(JoinLoyaltyContactEnums.contact.Contact)
|
||||
.optional()
|
||||
.default(JoinLoyaltyContactEnums.contact.Contact),
|
||||
contact: z.object({
|
||||
contact_field: z.string(),
|
||||
display_text: z.string().optional().nullable().default(null),
|
||||
footnote: z.string().optional().nullable().default(null),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
return {
|
||||
__typename: data.__typename,
|
||||
typename: data.typename,
|
||||
contact_field: data.contact.contact_field,
|
||||
display_text: data.contact.display_text,
|
||||
footnote: data.contact.footnote,
|
||||
}
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
export const joinLoyaltyContactSchema = z.object({
|
||||
typename: z
|
||||
.literal(SidebarEnums.blocks.JoinLoyaltyContact)
|
||||
.optional()
|
||||
.default(SidebarEnums.blocks.JoinLoyaltyContact),
|
||||
join_loyalty_contact: z
|
||||
.object({
|
||||
button: buttonSchema,
|
||||
preamble: z.string().optional(),
|
||||
title: z.string().optional(),
|
||||
})
|
||||
.merge(contactSchema),
|
||||
})
|
||||
|
||||
export const joinLoyaltyContactRefsSchema = z.object({
|
||||
join_loyalty_contact: z.object({
|
||||
button: linkConnectionRefsSchema,
|
||||
}),
|
||||
})
|
||||
9
server/routers/contentstack/schemas/system.ts
Normal file
9
server/routers/contentstack/schemas/system.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
export const systemSchema = z.object({
|
||||
content_type_uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
})
|
||||
Reference in New Issue
Block a user