diff --git a/components/Blocks/DynamicContent/SASTierComparison/index.tsx b/components/Blocks/DynamicContent/SASTierComparison/index.tsx new file mode 100644 index 000000000..e0438e598 --- /dev/null +++ b/components/Blocks/DynamicContent/SASTierComparison/index.tsx @@ -0,0 +1,25 @@ +import { serverClient } from "@/lib/trpc/server" + +import { SasTierComparison } from "@/components/SasTierComparison" + +type SASTierComparisonBlockProps = { + title: string + preamble: string +} +export default async function SASTierComparisonBlock({ + title, + preamble, +}: SASTierComparisonBlockProps) { + const tierComparison = + await serverClient().contentstack.partner.getSasTierComparison() + + if (!tierComparison) return null + + return ( + + ) +} diff --git a/components/Blocks/DynamicContent/index.tsx b/components/Blocks/DynamicContent/index.tsx index 3c9849c57..44dd15859 100644 --- a/components/Blocks/DynamicContent/index.tsx +++ b/components/Blocks/DynamicContent/index.tsx @@ -11,6 +11,7 @@ import ExpiringPoints from "@/components/Blocks/DynamicContent/Points/ExpiringPo import PointsOverview from "@/components/Blocks/DynamicContent/Points/Overview" import CurrentRewardsBlock from "@/components/Blocks/DynamicContent/Rewards/CurrentRewards" import NextLevelRewardsBlock from "@/components/Blocks/DynamicContent/Rewards/NextLevel" +import SASTierComparisonBlock from "@/components/Blocks/DynamicContent/SASTierComparison" import SignupFormWrapper from "@/components/Blocks/DynamicContent/SignupFormWrapper" import SignUpVerification from "@/components/Blocks/DynamicContent/SignUpVerification" import PreviousStays from "@/components/Blocks/DynamicContent/Stays/Previous" @@ -74,6 +75,13 @@ function DynamicContentBlocks(props: DynamicContentProps) { return case DynamicContentEnum.Blocks.components.upcoming_stays: return + case DynamicContentEnum.Blocks.components.sas_tier_comparison: + return ( + + ) default: return null } diff --git a/components/Blocks/index.tsx b/components/Blocks/index.tsx index 35037f803..93280b3ec 100644 --- a/components/Blocks/index.tsx +++ b/components/Blocks/index.tsx @@ -7,7 +7,6 @@ import ShortcutsList from "@/components/Blocks/ShortcutsList" import TextCols from "@/components/Blocks/TextCols" import UspGrid from "@/components/Blocks/UspGrid" import JsonToHtml from "@/components/JsonToHtml" -import { SasTierComparison } from "@/components/SasTierComparison" import AccordionSection from "./Accordion" import FullWidthCampaign from "./FullWidthCampaign" @@ -103,8 +102,6 @@ export default function Blocks({ blocks }: BlocksProps) { ) case BlocksEnums.block.UspGrid: return - case BlocksEnums.block.SasTierComparison: - return case BlocksEnums.block.FullWidthCampaign: return case BlocksEnums.block.JoinScandicFriends: diff --git a/components/SasTierComparison/index.tsx b/components/SasTierComparison/index.tsx index 3fb1bfb21..c9b685369 100644 --- a/components/SasTierComparison/index.tsx +++ b/components/SasTierComparison/index.tsx @@ -12,30 +12,28 @@ import Caption from "../TempDesignSystem/Text/Caption" import Subtitle from "../TempDesignSystem/Text/Subtitle" import Title from "../TempDesignSystem/Text/Title" -import styles from "./sas-tier-comparison.module.css" +import styles from "./sasTierComparison.module.css" import type { ReactNode } from "react" -import type { SasTierComparison } from "@/types/trpc/routers/contentstack/blocks" - -type SasTierComparisonContent = SasTierComparison["sas_tier_comparison"] +import type { SasTierComparison } from "@/types/trpc/routers/contentstack/partner" type TierComparisonProps = { - content: SasTierComparisonContent + title?: string + preamble?: string + tierComparison: NonNullable } -export function SasTierComparison({ content }: TierComparisonProps) { - const comparisonContent = content.sasTierComparison - - if (!comparisonContent) return null - +export function SasTierComparison({ + title, + preamble, + tierComparison, +}: TierComparisonProps) { return (
- {comparisonContent.title} - {comparisonContent.preamble && ( -

{comparisonContent.preamble}

- )} + {title} + {preamble &&

{preamble}

}
@@ -53,11 +51,11 @@ export function SasTierComparison({ content }: TierComparisonProps) { priority width={215} /> - {comparisonContent.scandic_column_title} - {comparisonContent.sas_column_title} + {tierComparison.scandic_column_title} + {tierComparison.sas_column_title}
- {comparisonContent.tier_matches.map((tierMatch, i) => ( + {tierComparison.tier_matches.map((tierMatch, i) => (
- {comparisonContent.cta?.href && ( + {tierComparison.cta?.href && ( )} @@ -79,9 +77,7 @@ export function SasTierComparison({ content }: TierComparisonProps) { ) } -type TierMatch = NonNullable< - SasTierComparisonContent["sasTierComparison"] ->["tier_matches"][number] +type TierMatch = NonNullable["tier_matches"][number] function TierDetails({ children, diff --git a/components/SasTierComparison/sas-tier-comparison.module.css b/components/SasTierComparison/sasTierComparison.module.css similarity index 100% rename from components/SasTierComparison/sas-tier-comparison.module.css rename to components/SasTierComparison/sasTierComparison.module.css diff --git a/lib/graphql/Fragments/Blocks/SasTierComparison.graphql b/lib/graphql/Fragments/Blocks/SasTierComparison.graphql deleted file mode 100644 index 7f8f6a9f6..000000000 --- a/lib/graphql/Fragments/Blocks/SasTierComparison.graphql +++ /dev/null @@ -1,35 +0,0 @@ -fragment SasTierComparison_ContentPage on ContentPageBlocksSasTierComparison { - __typename - sas_tier_comparison { - comparisonConnection { - totalCount - edges { - node { - __typename - ... on SasTierComparison { - title - preamble - scandic_column_title - sas_column_title - tier_matches { - title - scandic_friends_tier_name - sas_eb_tier_name - content { - json - } - link { - href - title - } - } - cta { - title - href - } - } - } - } - } - } -} diff --git a/lib/graphql/Query/ContentPage/ContentPage.graphql b/lib/graphql/Query/ContentPage/ContentPage.graphql index 85304010e..87b7f285f 100644 --- a/lib/graphql/Query/ContentPage/ContentPage.graphql +++ b/lib/graphql/Query/ContentPage/ContentPage.graphql @@ -9,7 +9,6 @@ #import "../../Fragments/Blocks/Table.graphql" #import "../../Fragments/Blocks/TextCols.graphql" #import "../../Fragments/Blocks/UspGrid.graphql" -#import "../../Fragments/Blocks/SasTierComparison.graphql" #import "../../Fragments/ContentPage/NavigationLinks.graphql" #import "../../Fragments/Sidebar/Content.graphql" @@ -76,15 +75,6 @@ query GetContentPageBlocksBatch2($locale: String!, $uid: String!) { } } -query GetContentPageBlocksBatch3($locale: String!, $uid: String!) { - content_page(uid: $uid, locale: $locale) { - blocks { - __typename - ...SasTierComparison_ContentPage - } - } -} - query GetContentPageRefs($locale: String!, $uid: String!) { content_page(locale: $locale, uid: $uid) { header { diff --git a/lib/graphql/Query/SASTierComparison.graphql b/lib/graphql/Query/SASTierComparison.graphql new file mode 100644 index 000000000..6434859fb --- /dev/null +++ b/lib/graphql/Query/SASTierComparison.graphql @@ -0,0 +1,24 @@ +query GetAllSasTierComparison($lang: String!) { + all_sas_tier_comparison(locale: $lang) { + items { + scandic_column_title + sas_column_title + tier_matches { + title + scandic_friends_tier_name + sas_eb_tier_name + content { + json + } + link { + href + title + } + } + cta { + title + href + } + } + } +} diff --git a/server/routers/contentstack/contentPage/output.ts b/server/routers/contentstack/contentPage/output.ts index 51033c77d..a1c027ade 100644 --- a/server/routers/contentstack/contentPage/output.ts +++ b/server/routers/contentstack/contentPage/output.ts @@ -19,7 +19,6 @@ import { dynamicContentSchema as blockDynamicContentSchema, } from "../schemas/blocks/dynamicContent" import { hotelListingSchema } from "../schemas/blocks/hotelListing" -import { sasTierComparisonSchema } from "../schemas/blocks/sasTierComparison" import { shortcutsRefsSchema, shortcutsSchema, @@ -106,14 +105,6 @@ export const contentPageAccordion = z }) .merge(accordionSchema) -export const contentPageLoyaltyTierComparison = z - .object({ - __typename: z.literal( - ContentPageEnum.ContentStack.blocks.SasTierComparison - ), - }) - .merge(sasTierComparisonSchema) - export const contentPageHotelListing = z .object({ __typename: z.literal(ContentPageEnum.ContentStack.blocks.HotelListing), @@ -129,7 +120,6 @@ export const blocksSchema = z.discriminatedUnion("__typename", [ contentPageTable, contentPageTextCols, contentPageUspGrid, - contentPageLoyaltyTierComparison, contentPageHotelListing, ]) diff --git a/server/routers/contentstack/contentPage/query.ts b/server/routers/contentstack/contentPage/query.ts index ea2698d39..02c7419d7 100644 --- a/server/routers/contentstack/contentPage/query.ts +++ b/server/routers/contentstack/contentPage/query.ts @@ -3,7 +3,6 @@ import { GetContentPage, GetContentPageBlocksBatch1, GetContentPageBlocksBatch2, - GetContentPageBlocksBatch3, } from "@/lib/graphql/Query/ContentPage/ContentPage.graphql" import { contentstackExtendedProcedureUID, router } from "@/server/trpc" @@ -73,17 +72,6 @@ export const contentPageQueryRouter = router({ }, }, }, - - { - document: GetContentPageBlocksBatch3, - variables: { locale: lang, uid }, - options: { - cache: "force-cache", - next: { - tags, - }, - }, - }, ]) const contentPage = contentPageSchema.safeParse(contentPageRequest.data) diff --git a/server/routers/contentstack/index.ts b/server/routers/contentstack/index.ts index 29bbbb1a4..df5749f5d 100644 --- a/server/routers/contentstack/index.ts +++ b/server/routers/contentstack/index.ts @@ -15,6 +15,7 @@ import { loyaltyLevelRouter } from "./loyaltyLevel" import { loyaltyPageRouter } from "./loyaltyPage" import { metadataRouter } from "./metadata" import { myPagesRouter } from "./myPages" +import { partnerRouter } from "./partner" import { rewardRouter } from "./reward" import { startPageRouter } from "./startPage" @@ -36,4 +37,5 @@ export const contentstackRouter = router({ rewards: rewardRouter, loyaltyLevels: loyaltyLevelRouter, startPage: startPageRouter, + partner: partnerRouter, }) diff --git a/server/routers/contentstack/partner/index.ts b/server/routers/contentstack/partner/index.ts new file mode 100644 index 000000000..2a87cfc8c --- /dev/null +++ b/server/routers/contentstack/partner/index.ts @@ -0,0 +1,5 @@ +import { mergeRouters } from "@/server/trpc" + +import { partnerQueryRouter } from "./query" + +export const partnerRouter = mergeRouters(partnerQueryRouter) diff --git a/server/routers/contentstack/partner/output.ts b/server/routers/contentstack/partner/output.ts new file mode 100644 index 000000000..67340aff6 --- /dev/null +++ b/server/routers/contentstack/partner/output.ts @@ -0,0 +1,31 @@ +import { z } from "zod" + +const link = z.object({ + href: z.string(), + title: z.string(), +}) + +export const validateSasTierComparisonSchema = z + .object({ + all_sas_tier_comparison: z.object({ + items: z.array( + z.object({ + scandic_column_title: z.string(), + sas_column_title: z.string(), + tier_matches: z.array( + z.object({ + scandic_friends_tier_name: z.string(), + sas_eb_tier_name: z.string(), + title: z.string(), + content: z.object({ + json: z.any(), // json + }), + link: link.optional(), + }) + ), + cta: link.optional(), + }) + ), + }), + }) + .transform((data) => data.all_sas_tier_comparison.items.at(0)) diff --git a/server/routers/contentstack/partner/query.ts b/server/routers/contentstack/partner/query.ts new file mode 100644 index 000000000..52424a9da --- /dev/null +++ b/server/routers/contentstack/partner/query.ts @@ -0,0 +1,86 @@ +import { metrics } from "@opentelemetry/api" +import { cache } from "react" + +import { GetAllSasTierComparison } from "@/lib/graphql/Query/SASTierComparison.graphql" +import { request } from "@/lib/graphql/request" +import { notFound } from "@/server/errors/trpc" +import { contentstackBaseProcedure, router } from "@/server/trpc" + +import { validateSasTierComparisonSchema } from "./output" + +import type { SasTierComparisonResponse } from "@/types/trpc/routers/contentstack/partner" +import type { Context } from "@/server/context" + +const meter = metrics.getMeter("trpc.partner") +const getSasTierComparisonCounter = meter.createCounter( + "trpc.contentstack.partner.getSasTierComparison" +) + +const getSasTierComparisonSuccessCounter = meter.createCounter( + "trpc.contentstack.partner.getSasTierComparison-success" +) +const getSasTierComparisonFailCounter = meter.createCounter( + "trpc.contentstack.partner.getSasTierComparison-fail" +) + +export const getSasTierComparison = cache(async (ctx: Context) => { + getSasTierComparisonCounter.add(1) + + const tag = `${ctx.lang}:sas_tier_comparison` + const sasTierComparisonConfigResponse = + await request( + GetAllSasTierComparison, + { lang: ctx.lang }, + { + next: { + tags: [tag], + }, + cache: "force-cache", + } + ) + + if (!sasTierComparisonConfigResponse.data) { + getSasTierComparisonFailCounter.add(1) + const notFoundError = notFound(sasTierComparisonConfigResponse) + console.error( + "contentstack.sas not found error", + JSON.stringify({ + query: { + lang: ctx.lang, + }, + error: { code: notFoundError.code }, + }) + ) + throw notFoundError + } + + const validatedSasTierComparison = validateSasTierComparisonSchema.safeParse( + sasTierComparisonConfigResponse.data + ) + + if (!validatedSasTierComparison.success) { + getSasTierComparisonFailCounter.add(1) + console.error(validatedSasTierComparison.error) + console.error( + "contentstack.sas validation error", + JSON.stringify({ + query: { + lang: ctx.lang, + }, + error: validatedSasTierComparison.error, + }) + ) + return null + } + + getSasTierComparisonSuccessCounter.add(1) + return validatedSasTierComparison.data +}) + +export const partnerQueryRouter = router({ + getSasTierComparison: contentstackBaseProcedure.query(async function ({ + ctx, + }) { + return getSasTierComparison(ctx) + }), +}) diff --git a/server/routers/contentstack/schemas/blocks/sasTierComparison.ts b/server/routers/contentstack/schemas/blocks/sasTierComparison.ts deleted file mode 100644 index f9b22de4a..000000000 --- a/server/routers/contentstack/schemas/blocks/sasTierComparison.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { z } from "zod" - -import { MembershipLevelEnum } from "@/constants/membershipLevels" - -import { BlocksEnums } from "@/types/enums/blocks" - -const link = z.object({ - href: z.string(), - title: z.string(), -}) - -export const sasTierComparisonSchema = z.object({ - typename: z - .literal(BlocksEnums.block.SasTierComparison) - .optional() - .default(BlocksEnums.block.SasTierComparison), - sas_tier_comparison: z - .object({ - comparisonConnection: z.object({ - edges: z.array( - z.object({ - node: z.object({ - title: z.string(), - preamble: z.string().optional(), - scandic_column_title: z.string(), - sas_column_title: z.string(), - tier_matches: z.array( - z.object({ - scandic_friends_tier_name: z.string(), - sas_eb_tier_name: z.string(), - title: z.string(), - content: z.object({ - json: z.any(), // json - }), - link: link.optional(), - }) - ), - cta: link.optional(), - }), - }) - ), - }), - }) - .transform((data) => { - return { - sasTierComparison: data.comparisonConnection.edges.at(0)?.node ?? null, - } - }), -}) diff --git a/types/enums/blocks.ts b/types/enums/blocks.ts index b833e4a76..4bb7559fd 100644 --- a/types/enums/blocks.ts +++ b/types/enums/blocks.ts @@ -9,7 +9,6 @@ export namespace BlocksEnums { TextCols = "TextCols", TextContent = "TextContent", UspGrid = "UspGrid", - SasTierComparison = "SasTierComparison", HotelListing = "HotelListing", FullWidthCampaign = "FullWidthCampaign", CarouselCards = "CarouselCards", diff --git a/types/enums/contentPage.ts b/types/enums/contentPage.ts index 918c68790..55fb12c35 100644 --- a/types/enums/contentPage.ts +++ b/types/enums/contentPage.ts @@ -9,7 +9,6 @@ export namespace ContentPageEnum { TextCols = "ContentPageBlocksTextCols", UspGrid = "ContentPageBlocksUspGrid", Table = "ContentPageBlocksTable", - SasTierComparison = "ContentPageBlocksSasTierComparison", HotelListing = "ContentPageBlocksHotelListing", } diff --git a/types/enums/dynamicContent.ts b/types/enums/dynamicContent.ts index 0dcd29937..dc71a07e5 100644 --- a/types/enums/dynamicContent.ts +++ b/types/enums/dynamicContent.ts @@ -16,6 +16,7 @@ export namespace DynamicContentEnum { sign_up_verification = "sign_up_verification", soonest_stays = "soonest_stays", upcoming_stays = "upcoming_stays", + sas_tier_comparison = "sas_tier_comparison", } /** Type needed to satisfy zod enum type */ @@ -35,6 +36,7 @@ export namespace DynamicContentEnum { components.sign_up_verification, components.soonest_stays, components.upcoming_stays, + components.sas_tier_comparison, ] } diff --git a/types/trpc/routers/contentstack/blocks.ts b/types/trpc/routers/contentstack/blocks.ts index c7189c379..b22595325 100644 --- a/types/trpc/routers/contentstack/blocks.ts +++ b/types/trpc/routers/contentstack/blocks.ts @@ -6,7 +6,6 @@ import type { carouselCardsSchema } from "@/server/routers/contentstack/schemas/ import type { contentSchema } from "@/server/routers/contentstack/schemas/blocks/content" import type { dynamicContentSchema } from "@/server/routers/contentstack/schemas/blocks/dynamicContent" import type { hotelListingSchema } from "@/server/routers/contentstack/schemas/blocks/hotelListing" -import type { sasTierComparisonSchema } from "@/server/routers/contentstack/schemas/blocks/sasTierComparison" import type { shortcutsSchema } from "@/server/routers/contentstack/schemas/blocks/shortcuts" import type { tableSchema } from "@/server/routers/contentstack/schemas/blocks/table" import type { textColsSchema } from "@/server/routers/contentstack/schemas/blocks/textCols" @@ -24,6 +23,4 @@ export interface TextCols extends z.output {} export interface UspGrid extends z.output {} interface GetHotelListing extends z.output {} export type HotelListing = GetHotelListing["hotel_listing"] -export interface SasTierComparison - extends z.output {} export interface CarouselCards extends z.output {} diff --git a/types/trpc/routers/contentstack/partner.ts b/types/trpc/routers/contentstack/partner.ts new file mode 100644 index 000000000..d67f77329 --- /dev/null +++ b/types/trpc/routers/contentstack/partner.ts @@ -0,0 +1,9 @@ +import type { z } from "zod" + +import type { validateSasTierComparisonSchema } from "@/server/routers/contentstack/partner/output" + +export type SasTierComparisonResponse = z.input< + typeof validateSasTierComparisonSchema +> + +export type SasTierComparison = z.output