Merged in feat/reusable-card (pull request #190)
Feat/reusable card and button design Approved-by: Michael Zetterberg
This commit is contained in:
@@ -13,37 +13,28 @@ import { PageLinkEnum } from "@/types/requests/pageLinks"
|
||||
import { EdgesWithTotalCount } from "@/types/requests/utils/edges"
|
||||
import { RTEDocument } from "@/types/rte/node"
|
||||
|
||||
const loyaltyPageBlockCardGrid = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid),
|
||||
card_grid: z.object({
|
||||
title: z.string().nullable(),
|
||||
subtitle: z.string().nullable(),
|
||||
cards: z.array(
|
||||
z.object({
|
||||
title: z.string().nullable(),
|
||||
subtitle: z.string().nullable(),
|
||||
referenceConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
}),
|
||||
url: z.string(),
|
||||
title: z.string(),
|
||||
__typename: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
totalCount: z.number(),
|
||||
const pageLink = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
}),
|
||||
open_in_new_tab: z.boolean(),
|
||||
cta_text: z.string().nullable(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
web: z
|
||||
.object({
|
||||
original_url: z.string().nullable(),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
url: z.string(),
|
||||
title: z.string(),
|
||||
__typename: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
const loyaltyPageDynamicContent = z.object({
|
||||
__typename: z.literal(
|
||||
LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent
|
||||
@@ -54,21 +45,7 @@ const loyaltyPageDynamicContent = z.object({
|
||||
component: z.nativeEnum(LoyaltyComponentEnum),
|
||||
link: z.object({
|
||||
text: z.string().nullable(),
|
||||
pageConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
uid: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
}),
|
||||
url: z.string(),
|
||||
title: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
pageConnection: pageLink,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
@@ -80,26 +57,7 @@ const loyaltyPageShortcuts = z.object({
|
||||
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),
|
||||
}),
|
||||
url: z.string(),
|
||||
web: z
|
||||
.object({
|
||||
original_url: z.string().nullable(),
|
||||
})
|
||||
.nullable(),
|
||||
title: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
totalCount: z.number(),
|
||||
}),
|
||||
linkConnection: pageLink,
|
||||
text: z.string().nullable(),
|
||||
open_in_new_tab: z.boolean(),
|
||||
})
|
||||
@@ -107,6 +65,59 @@ const loyaltyPageShortcuts = z.object({
|
||||
}),
|
||||
})
|
||||
|
||||
const cardBlock = z.object({
|
||||
heading: z.string().nullable(),
|
||||
body_text: z.string().nullable(),
|
||||
background_image: z.any(),
|
||||
scripted_top_title: z.string().nullable(),
|
||||
primary_button: z
|
||||
.object({
|
||||
is_contentstack_link: z.boolean(),
|
||||
cta_text: z.string().nullable(),
|
||||
open_in_new_tab: z.boolean(),
|
||||
external_link: z.object({
|
||||
title: z.string().nullable(),
|
||||
href: z.string().nullable(),
|
||||
}),
|
||||
linkConnection: pageLink,
|
||||
})
|
||||
.nullable(),
|
||||
secondary_button: z
|
||||
.object({
|
||||
is_contentstack_link: z.boolean(),
|
||||
cta_text: z.string().nullable(),
|
||||
open_in_new_tab: z.boolean().nullable(),
|
||||
external_link: z.object({
|
||||
title: z.string().nullable(),
|
||||
href: z.string().nullable(),
|
||||
}),
|
||||
linkConnection: pageLink,
|
||||
})
|
||||
.nullable(),
|
||||
|
||||
system: z.object({
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
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(),
|
||||
cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: cardBlock,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
const loyaltyPageBlockTextContent = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent),
|
||||
content: z.object({
|
||||
@@ -121,10 +132,10 @@ const loyaltyPageBlockTextContent = z.object({
|
||||
})
|
||||
|
||||
const loyaltyPageBlockItem = z.discriminatedUnion("__typename", [
|
||||
loyaltyPageBlockCardGrid,
|
||||
loyaltyPageDynamicContent,
|
||||
loyaltyPageBlockTextContent,
|
||||
loyaltyPageShortcuts,
|
||||
loyaltyPageCards,
|
||||
])
|
||||
|
||||
const loyaltyPageSidebarTextContent = z.object({
|
||||
@@ -154,7 +165,6 @@ const loyaltyPageJoinLoyaltyContact = z.object({
|
||||
),
|
||||
contact: z.object({
|
||||
display_text: z.string().nullable(),
|
||||
|
||||
contact_field: z.string(),
|
||||
}),
|
||||
})
|
||||
@@ -178,26 +188,6 @@ export const validateLoyaltyPageSchema = z.object({
|
||||
})
|
||||
|
||||
// Block types
|
||||
type CardGridRaw = z.infer<typeof loyaltyPageBlockCardGrid>
|
||||
|
||||
export type CardGridCard = Omit<
|
||||
CardGridRaw["card_grid"]["cards"][number],
|
||||
"referenceConnection"
|
||||
> & {
|
||||
link:
|
||||
| {
|
||||
href: string
|
||||
title: string
|
||||
}
|
||||
| undefined
|
||||
}
|
||||
|
||||
export type CardGrid = Omit<CardGridRaw, "card_grid"> & {
|
||||
card_grid: Omit<CardGridRaw["card_grid"], "cards"> & {
|
||||
cards: CardGridCard[]
|
||||
}
|
||||
}
|
||||
|
||||
type DynamicContentRaw = z.infer<typeof loyaltyPageDynamicContent>
|
||||
|
||||
export type DynamicContent = Omit<DynamicContentRaw, "dynamic_content"> & {
|
||||
@@ -222,6 +212,34 @@ export interface RteBlockContent extends BlockContentRaw {
|
||||
}
|
||||
}
|
||||
|
||||
type CardsGridRaw = z.infer<typeof loyaltyPageCards>
|
||||
|
||||
export type CardsRaw =
|
||||
CardsGridRaw["cards_grid"]["cardConnection"]["edges"][number]["node"]
|
||||
|
||||
export type CardsGrid = Omit<CardsGridRaw, "cards_grid"> & {
|
||||
cards_grid: Omit<CardsGridRaw["cards_grid"], "cardConnection"> & {
|
||||
cards: (Omit<CardsRaw, "primaryButton" | "secondaryButton"> & {
|
||||
primaryButton:
|
||||
| {
|
||||
openInNewTab: boolean
|
||||
title: string
|
||||
href: string
|
||||
isExternal: boolean
|
||||
}
|
||||
| undefined
|
||||
secondaryButton:
|
||||
| {
|
||||
openInNewTab: boolean
|
||||
title: string
|
||||
href: string
|
||||
isExternal: boolean
|
||||
}
|
||||
| undefined
|
||||
})[]
|
||||
}
|
||||
}
|
||||
|
||||
type ShortcutsRaw = z.infer<typeof loyaltyPageShortcuts>
|
||||
|
||||
export type Shortcuts = Omit<ShortcutsRaw, "shortcuts"> & {
|
||||
@@ -235,7 +253,7 @@ export type Shortcuts = Omit<ShortcutsRaw, "shortcuts"> & {
|
||||
}
|
||||
}
|
||||
|
||||
export type Block = CardGrid | RteBlockContent | DynamicContent | Shortcuts
|
||||
export type Block = RteBlockContent | DynamicContent | Shortcuts | CardsGrid
|
||||
|
||||
// Sidebar block types
|
||||
type SidebarContentRaw = z.infer<typeof loyaltyPageSidebarTextContent>
|
||||
@@ -275,14 +293,34 @@ const pageConnectionRefs = z.object({
|
||||
),
|
||||
})
|
||||
|
||||
const loyaltyPageBlockCardGridRefs = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid),
|
||||
card_grid: z.object({
|
||||
cards: z.array(
|
||||
z.object({
|
||||
referenceConnection: pageConnectionRefs,
|
||||
})
|
||||
),
|
||||
const cardBlockRefs = z.object({
|
||||
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 loyaltyPageCardsRefs = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid),
|
||||
cards_grid: z.object({
|
||||
cardConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: cardBlockRefs,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -318,10 +356,10 @@ const loyaltyPageBlockTextContentRefs = z.object({
|
||||
})
|
||||
|
||||
const loyaltyPageBlocRefsItem = z.discriminatedUnion("__typename", [
|
||||
loyaltyPageBlockCardGridRefs,
|
||||
loyaltyPageDynamicContentRefs,
|
||||
loyaltyPageBlockTextContentRefs,
|
||||
loyaltyPageShortcutsRefs,
|
||||
loyaltyPageCardsRefs,
|
||||
])
|
||||
|
||||
const loyaltyPageSidebarTextContentRef = z.object({
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { _ } from "@/lib/translation"
|
||||
import { internalServerError, notFound } from "@/server/errors/trpc"
|
||||
import { contentstackProcedure, publicProcedure, router } from "@/server/trpc"
|
||||
import { contentstackProcedure, router } from "@/server/trpc"
|
||||
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
|
||||
import { removeEmptyObjects } from "../../utils"
|
||||
import {
|
||||
CardsRaw,
|
||||
type LoyaltyPage,
|
||||
type LoyaltyPageDataRaw,
|
||||
type LoyaltyPageRefsDataRaw,
|
||||
@@ -31,6 +32,26 @@ import { Embeds } from "@/types/requests/embeds"
|
||||
import { Edges } from "@/types/requests/utils/edges"
|
||||
import { RTEDocument } from "@/types/rte/node"
|
||||
|
||||
function makeButtonObject(
|
||||
button: CardsRaw["primary_button" | "secondary_button"]
|
||||
) {
|
||||
if (!button) return undefined
|
||||
return {
|
||||
openInNewTab: button.open_in_new_tab,
|
||||
title:
|
||||
button.cta_text ||
|
||||
(button.is_contentstack_link && button.linkConnection.edges.length
|
||||
? button.linkConnection.edges[0].node.title
|
||||
: button.external_link.title),
|
||||
href:
|
||||
button.is_contentstack_link && button.linkConnection.edges.length
|
||||
? button.linkConnection.edges[0].node.web?.original_url ||
|
||||
`/${button.linkConnection.edges[0].node.system.locale}${button.linkConnection.edges[0].node.url}`
|
||||
: button.external_link.href,
|
||||
isExternal: !button.is_contentstack_link,
|
||||
}
|
||||
}
|
||||
|
||||
export const loyaltyPageQueryRouter = router({
|
||||
get: contentstackProcedure.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
@@ -60,6 +81,8 @@ export const loyaltyPageQueryRouter = router({
|
||||
const validatedLoyaltyPageRefs =
|
||||
validateLoyaltyPageRefsSchema.safeParse(cleanedData)
|
||||
if (!validatedLoyaltyPageRefs.success) {
|
||||
console.error("Bad validation for `GetLoyaltyPageRefs`")
|
||||
console.error(validatedLoyaltyPageRefs.error)
|
||||
throw internalServerError(validatedLoyaltyPageRefs.error)
|
||||
}
|
||||
|
||||
@@ -114,30 +137,12 @@ export const loyaltyPageQueryRouter = router({
|
||||
const blocks = validatedLoyaltyPage.data.loyalty_page.blocks
|
||||
? validatedLoyaltyPage.data.loyalty_page.blocks.map((block) => {
|
||||
switch (block.__typename) {
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid:
|
||||
return {
|
||||
...block,
|
||||
card_grid: {
|
||||
...block.card_grid,
|
||||
cards: block.card_grid.cards.map((card) => {
|
||||
return {
|
||||
...card,
|
||||
link: card.referenceConnection.totalCount
|
||||
? {
|
||||
href: `/${card.referenceConnection.edges[0].node.system.locale}${card.referenceConnection.edges[0].node.url}`,
|
||||
title: card.cta_text || _("Read more"),
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
}),
|
||||
},
|
||||
}
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent:
|
||||
return {
|
||||
...block,
|
||||
dynamic_content: {
|
||||
...block.dynamic_content,
|
||||
link: block.dynamic_content.link.pageConnection.totalCount
|
||||
link: block.dynamic_content.link.pageConnection.edges.length
|
||||
? {
|
||||
text: block.dynamic_content.link.text,
|
||||
href: `/${block.dynamic_content.link.pageConnection.edges[0].node.system.locale}${block.dynamic_content.link.pageConnection.edges[0].node.url}`,
|
||||
@@ -174,6 +179,24 @@ export const loyaltyPageQueryRouter = router({
|
||||
})),
|
||||
},
|
||||
}
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid:
|
||||
return {
|
||||
...block,
|
||||
cards_grid: {
|
||||
...block.cards_grid,
|
||||
cards: block.cards_grid.cardConnection.edges.map(
|
||||
({ node: card }) => {
|
||||
return {
|
||||
...card,
|
||||
primaryButton: makeButtonObject(card.primary_button),
|
||||
secondaryButton: makeButtonObject(
|
||||
card.secondary_button
|
||||
),
|
||||
}
|
||||
}
|
||||
),
|
||||
},
|
||||
}
|
||||
default:
|
||||
return block
|
||||
}
|
||||
|
||||
@@ -15,12 +15,16 @@ export function getConnections(refs: LoyaltyPageRefsDataRaw) {
|
||||
}
|
||||
break
|
||||
}
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid: {
|
||||
item.card_grid.cards.forEach((card) => {
|
||||
if (card.referenceConnection.edges.length) {
|
||||
connections.push(card.referenceConnection)
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid: {
|
||||
connections.push(item.cards_grid.cardConnection)
|
||||
item.cards_grid.cardConnection.edges.forEach((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
|
||||
}
|
||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksShortcuts: {
|
||||
|
||||
Reference in New Issue
Block a user