feat(SW-66, SW-348): search functionality and ui
This commit is contained in:
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user