import { metrics } from "@opentelemetry/api" import { Lang } from "@/constants/languages" import { GetLoyaltyPage, GetLoyaltyPageRefs, } from "@/lib/graphql/Query/LoyaltyPage.graphql" import { request } from "@/lib/graphql/request" import { notFound } from "@/server/errors/trpc" import { contentstackExtendedProcedureUID, router } from "@/server/trpc" import { generateRefsResponseTag, generateTag, generateTags, } 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 { LoyaltyBlocksTypenameEnum, LoyaltyCardsGridEnum, SidebarTypenameEnum, } from "@/types/components/loyalty/enums" import { TrackingChannelEnum, TrackingSDKPageData, } from "@/types/components/tracking" const meter = metrics.getMeter("trpc.loyaltyPage") // OpenTelemetry metrics: LoyaltyPage const getLoyaltyPageRefsCounter = meter.createCounter( "trpc.contentstack.loyaltyPage.get" ) const getLoyaltyPageRefsSuccessCounter = meter.createCounter( "trpc.contentstack.loyaltyPage.get-success" ) const getLoyaltyPageRefsFailCounter = meter.createCounter( "trpc.contentstack.loyaltyPage.get-fail" ) const getLoyaltyPageCounter = meter.createCounter( "trpc.contentstack.loyaltyPage.get" ) const getLoyaltyPageSuccessCounter = meter.createCounter( "trpc.contentstack.loyaltyPage.get-success" ) const getLoyaltyPageFailCounter = meter.createCounter( "trpc.contentstack.loyaltyPage.get-fail" ) export const loyaltyPageQueryRouter = router({ get: contentstackExtendedProcedureUID.query(async ({ ctx }) => { const { lang, uid } = ctx getLoyaltyPageRefsCounter.add(1, { lang, uid }) console.info( "contentstack.loyaltyPage.refs start", JSON.stringify({ query: { lang, uid }, }) ) const refsResponse = await request( GetLoyaltyPageRefs, { locale: lang, uid, }, { tags: [generateRefsResponseTag(lang, uid)], } ) if (!refsResponse.data) { const notFoundError = notFound(refsResponse) getLoyaltyPageRefsFailCounter.add(1, { lang, uid, error_type: "http_error", error: JSON.stringify({ code: notFoundError.code, }), }) console.error( "contentstack.loyaltyPage.refs not found error", JSON.stringify({ query: { lang, uid, }, error: { code: notFoundError.code }, }) ) throw notFoundError } const cleanedData = removeEmptyObjects(refsResponse.data) const validatedLoyaltyPageRefs = validateLoyaltyPageRefsSchema.safeParse(cleanedData) if (!validatedLoyaltyPageRefs.success) { getLoyaltyPageRefsFailCounter.add(1, { lang, uid, error_type: "validation_error", error: JSON.stringify(validatedLoyaltyPageRefs.error), }) console.error( "contentstack.loyaltyPage.refs validation error", JSON.stringify({ query: { lang, uid }, error: validatedLoyaltyPageRefs.error, }) ) return null } getLoyaltyPageRefsSuccessCounter.add(1, { lang, uid }) console.info( "contentstack.loyaltyPage.refs success", JSON.stringify({ query: { lang, uid }, }) ) const connections = getConnections(validatedLoyaltyPageRefs.data) const tags = [ generateTags(lang, connections), generateTag(lang, validatedLoyaltyPageRefs.data.loyalty_page.system.uid), ].flat() getLoyaltyPageCounter.add(1, { lang, uid }) console.info( "contentstack.loyaltyPage start", JSON.stringify({ query: { lang, uid }, }) ) const response = await request( GetLoyaltyPage, { locale: lang, uid, }, { tags } ) if (!response.data) { const notFoundError = notFound(response) getLoyaltyPageFailCounter.add(1, { lang, uid, error_type: "http_error", error: JSON.stringify({ code: notFoundError.code }), }) console.error( "contentstack.loyaltyPage not found error", JSON.stringify({ query: { lang, uid }, 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) if (!validatedLoyaltyPage.success) { getLoyaltyPageFailCounter.add(1, { lang, uid, error_type: "validation_error", error: JSON.stringify(validatedLoyaltyPage.error), }) console.error( "contentstack.loyaltyPage validation error", JSON.stringify({ query: { lang, uid }, error: validatedLoyaltyPage.error, }) ) return null } 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, channel: TrackingChannelEnum["scandic-friends"], pageType: "loyaltycontentpage", } getLoyaltyPageSuccessCounter.add(1, { lang, uid }) console.info( "contentstack.loyaltyPage success", JSON.stringify({ query: { lang, uid } }) ) // Assert LoyaltyPage type to get correct typings for RTE fields return { loyaltyPage, tracking: loyaltyTrackingData, } }), })