Merged in fix/move-sas-comparison-to-dynamic-content (pull request #1279)
Move SASTierComparison block to DynamicContent Approved-by: Erik Tiekstra
This commit is contained in:
25
components/Blocks/DynamicContent/SASTierComparison/index.tsx
Normal file
25
components/Blocks/DynamicContent/SASTierComparison/index.tsx
Normal file
@@ -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 (
|
||||
<SasTierComparison
|
||||
title={title}
|
||||
preamble={preamble}
|
||||
tierComparison={tierComparison}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -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 <SoonestStays {...dynamic_content} />
|
||||
case DynamicContentEnum.Blocks.components.upcoming_stays:
|
||||
return <UpcomingStays {...dynamic_content} />
|
||||
case DynamicContentEnum.Blocks.components.sas_tier_comparison:
|
||||
return (
|
||||
<SASTierComparisonBlock
|
||||
title={dynamic_content.title}
|
||||
preamble={dynamic_content.subtitle}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -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 <UspGrid usp_grid={block.usp_grid} />
|
||||
case BlocksEnums.block.SasTierComparison:
|
||||
return <SasTierComparison content={block.sas_tier_comparison} />
|
||||
case BlocksEnums.block.FullWidthCampaign:
|
||||
return <FullWidthCampaign content={block.full_width_campaign} />
|
||||
case BlocksEnums.block.JoinScandicFriends:
|
||||
|
||||
@@ -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<SasTierComparison>
|
||||
}
|
||||
|
||||
export function SasTierComparison({ content }: TierComparisonProps) {
|
||||
const comparisonContent = content.sasTierComparison
|
||||
|
||||
if (!comparisonContent) return null
|
||||
|
||||
export function SasTierComparison({
|
||||
title,
|
||||
preamble,
|
||||
tierComparison,
|
||||
}: TierComparisonProps) {
|
||||
return (
|
||||
<SectionContainer className={styles.comparisonSection}>
|
||||
<div className={styles.header}>
|
||||
<Title level="h2">{comparisonContent.title}</Title>
|
||||
{comparisonContent.preamble && (
|
||||
<p className={styles.preamble}>{comparisonContent.preamble}</p>
|
||||
)}
|
||||
<Title level="h2">{title}</Title>
|
||||
{preamble && <p className={styles.preamble}>{preamble}</p>}
|
||||
</div>
|
||||
<div>
|
||||
<div className={styles.columnHeaders}>
|
||||
@@ -53,11 +51,11 @@ export function SasTierComparison({ content }: TierComparisonProps) {
|
||||
priority
|
||||
width={215}
|
||||
/>
|
||||
<ColumnTitle>{comparisonContent.scandic_column_title}</ColumnTitle>
|
||||
<ColumnTitle>{comparisonContent.sas_column_title}</ColumnTitle>
|
||||
<ColumnTitle>{tierComparison.scandic_column_title}</ColumnTitle>
|
||||
<ColumnTitle>{tierComparison.sas_column_title}</ColumnTitle>
|
||||
</div>
|
||||
<div className={styles.tierMatchList}>
|
||||
{comparisonContent.tier_matches.map((tierMatch, i) => (
|
||||
{tierComparison.tier_matches.map((tierMatch, i) => (
|
||||
<TierDetails key={i} tierMatch={tierMatch}>
|
||||
<JsonToHtml
|
||||
nodes={tierMatch.content.json?.children}
|
||||
@@ -68,10 +66,10 @@ export function SasTierComparison({ content }: TierComparisonProps) {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{comparisonContent.cta?.href && (
|
||||
{tierComparison.cta?.href && (
|
||||
<Button theme="primaryLight" asChild className={styles.ctaButton}>
|
||||
<Link href={comparisonContent.cta.href} color="white">
|
||||
{comparisonContent.cta.title}
|
||||
<Link href={tierComparison.cta.href} color="white">
|
||||
{tierComparison.cta.title}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
@@ -79,9 +77,7 @@ export function SasTierComparison({ content }: TierComparisonProps) {
|
||||
)
|
||||
}
|
||||
|
||||
type TierMatch = NonNullable<
|
||||
SasTierComparisonContent["sasTierComparison"]
|
||||
>["tier_matches"][number]
|
||||
type TierMatch = NonNullable<SasTierComparison>["tier_matches"][number]
|
||||
|
||||
function TierDetails({
|
||||
children,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
24
lib/graphql/Query/SASTierComparison.graphql
Normal file
24
lib/graphql/Query/SASTierComparison.graphql
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
])
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
5
server/routers/contentstack/partner/index.ts
Normal file
5
server/routers/contentstack/partner/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { mergeRouters } from "@/server/trpc"
|
||||
|
||||
import { partnerQueryRouter } from "./query"
|
||||
|
||||
export const partnerRouter = mergeRouters(partnerQueryRouter)
|
||||
31
server/routers/contentstack/partner/output.ts
Normal file
31
server/routers/contentstack/partner/output.ts
Normal file
@@ -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))
|
||||
86
server/routers/contentstack/partner/query.ts
Normal file
86
server/routers/contentstack/partner/query.ts
Normal file
@@ -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<SasTierComparisonResponse>(
|
||||
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)
|
||||
}),
|
||||
})
|
||||
@@ -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,
|
||||
}
|
||||
}),
|
||||
})
|
||||
@@ -9,7 +9,6 @@ export namespace BlocksEnums {
|
||||
TextCols = "TextCols",
|
||||
TextContent = "TextContent",
|
||||
UspGrid = "UspGrid",
|
||||
SasTierComparison = "SasTierComparison",
|
||||
HotelListing = "HotelListing",
|
||||
FullWidthCampaign = "FullWidthCampaign",
|
||||
CarouselCards = "CarouselCards",
|
||||
|
||||
@@ -9,7 +9,6 @@ export namespace ContentPageEnum {
|
||||
TextCols = "ContentPageBlocksTextCols",
|
||||
UspGrid = "ContentPageBlocksUspGrid",
|
||||
Table = "ContentPageBlocksTable",
|
||||
SasTierComparison = "ContentPageBlocksSasTierComparison",
|
||||
HotelListing = "ContentPageBlocksHotelListing",
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -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<typeof textColsSchema> {}
|
||||
export interface UspGrid extends z.output<typeof uspGridSchema> {}
|
||||
interface GetHotelListing extends z.output<typeof hotelListingSchema> {}
|
||||
export type HotelListing = GetHotelListing["hotel_listing"]
|
||||
export interface SasTierComparison
|
||||
extends z.output<typeof sasTierComparisonSchema> {}
|
||||
export interface CarouselCards extends z.output<typeof carouselCardsSchema> {}
|
||||
|
||||
9
types/trpc/routers/contentstack/partner.ts
Normal file
9
types/trpc/routers/contentstack/partner.ts
Normal file
@@ -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<typeof validateSasTierComparisonSchema>
|
||||
Reference in New Issue
Block a user