diff --git a/components/Blocks/DynamicContent/Rewards/Redeem/Flows/Tier.tsx b/components/Blocks/DynamicContent/Rewards/Redeem/Flows/Tier.tsx
index edf0680b5..69831bd57 100644
--- a/components/Blocks/DynamicContent/Rewards/Redeem/Flows/Tier.tsx
+++ b/components/Blocks/DynamicContent/Rewards/Redeem/Flows/Tier.tsx
@@ -2,6 +2,7 @@
import { useIntl } from "react-intl"
+import JsonToHtml from "@/components/JsonToHtml"
import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
@@ -53,7 +54,12 @@ export default function Tier({
)}
{redeemStep === "confirmation" && (
-
{reward.redeem_description}
+
)}
{redeemStep === "redeemed" &&
@@ -63,7 +69,10 @@ export default function Tier({
)}
>
) : (
- {reward.redeem_description}
+
)}
diff --git a/components/JsonToHtml/renderOptions.tsx b/components/JsonToHtml/renderOptions.tsx
index 4b9a8d308..315c37e4e 100644
--- a/components/JsonToHtml/renderOptions.tsx
+++ b/components/JsonToHtml/renderOptions.tsx
@@ -66,9 +66,11 @@ function extractPossibleAttributes(attrs: Attributes | undefined) {
props.className = attrs["class-name"]
} else if (attrs.classname) {
props.className = attrs.classname
- } else if (attrs?.style?.["text-align"]) {
+ }
+
+ if (attrs.style?.["text-align"]) {
props.style = {
- textAlign: attrs?.style?.["text-align"],
+ textAlign: attrs.style["text-align"],
}
}
diff --git a/lib/graphql/Query/RewardsWithRedeem.graphql b/lib/graphql/Query/RewardsWithRedeem.graphql
index b6ad7e4ae..91ed59491 100644
--- a/lib/graphql/Query/RewardsWithRedeem.graphql
+++ b/lib/graphql/Query/RewardsWithRedeem.graphql
@@ -1,3 +1,25 @@
+#import "../Fragments/System.graphql"
+
+#import "../Fragments/PageLink/AccountPageLink.graphql"
+#import "../Fragments/PageLink/CollectionPageLink.graphql"
+#import "../Fragments/PageLink/ContentPageLink.graphql"
+#import "../Fragments/PageLink/DestinationCityPageLink.graphql"
+#import "../Fragments/PageLink/DestinationCountryPageLink.graphql"
+#import "../Fragments/PageLink/DestinationOverviewPageLink.graphql"
+#import "../Fragments/PageLink/HotelPageLink.graphql"
+#import "../Fragments/PageLink/LoyaltyPageLink.graphql"
+#import "../Fragments/PageLink/StartPageLink.graphql"
+
+#import "../Fragments/AccountPage/Ref.graphql"
+#import "../Fragments/CollectionPage/Ref.graphql"
+#import "../Fragments/ContentPage/Ref.graphql"
+#import "../Fragments/DestinationCityPage/Ref.graphql"
+#import "../Fragments/DestinationCountryPage/Ref.graphql"
+#import "../Fragments/DestinationOverviewPage/Ref.graphql"
+#import "../Fragments/HotelPage/Ref.graphql"
+#import "../Fragments/LoyaltyPage/Ref.graphql"
+#import "../Fragments/StartPage/Ref.graphql"
+
query GetRewards($locale: String!, $rewardIds: [String!]) {
all_reward(locale: $locale, where: { reward_id_in: $rewardIds }) {
items {
@@ -7,10 +29,56 @@ query GetRewards($locale: String!, $rewardIds: [String!]) {
label
grouped_label
description
- redeem_description
+ redeem_description {
+ json
+ embedded_itemsConnection {
+ edges {
+ node {
+ __typename
+ ...AccountPageLink
+ ...CollectionPageLink
+ ...ContentPageLink
+ ...DestinationCityPageLink
+ ...DestinationCountryPageLink
+ ...DestinationOverviewPageLink
+ ...HotelPageLink
+ ...LoyaltyPageLink
+ ...StartPageLink
+ }
+ }
+ }
+ }
grouped_description
value
reward_id
}
}
}
+
+query GetRewardsRef($locale: String!, $rewardIds: [String!]) {
+ all_reward(locale: $locale, where: { reward_id_in: $rewardIds }) {
+ items {
+ redeem_description {
+ embedded_itemsConnection {
+ edges {
+ node {
+ __typename
+ ...AccountPageRef
+ ...CollectionPageRef
+ ...ContentPageRef
+ ...DestinationCityPageRef
+ ...DestinationCountryPageRef
+ ...DestinationOverviewPageRef
+ ...HotelPageRef
+ ...LoyaltyPageRef
+ ...StartPageRef
+ }
+ }
+ }
+ }
+ system {
+ ...System
+ }
+ }
+ }
+}
diff --git a/server/routers/contentstack/reward/output.ts b/server/routers/contentstack/reward/output.ts
index 3152d5b5c..25e07a22e 100644
--- a/server/routers/contentstack/reward/output.ts
+++ b/server/routers/contentstack/reward/output.ts
@@ -2,6 +2,13 @@ import { z } from "zod"
import { MembershipLevelEnum } from "@/constants/membershipLevels"
+import {
+ linkRefsUnionSchema,
+ linkUnionSchema,
+ transformPageLink,
+} from "../schemas/pageLinks"
+import { systemSchema } from "../schemas/system"
+
const Coupon = z.object({
code: z.string().optional(),
status: z.string().optional(),
@@ -133,10 +140,22 @@ export const validateCmsRewardsWithRedeemSchema = z
reward_id: z.string(),
grouped_label: z.string().optional(),
description: z.string().optional(),
- redeem_description: z
- .string()
- .nullable()
- .transform((val) => val || ""),
+ redeem_description: z.object({
+ json: z.any(), // JSON
+ embedded_itemsConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: linkUnionSchema.transform((data) => {
+ const link = transformPageLink(data)
+ if (link) {
+ return link
+ }
+ return data
+ }),
+ })
+ ),
+ }),
+ }),
grouped_description: z.string().optional(),
value: z.string().optional(),
})
@@ -156,6 +175,30 @@ export type CmsRewardsWithRedeemResponse = z.input<
typeof validateCmsRewardsWithRedeemSchema
>
+export const rewardWithRedeemRefsSchema = z.object({
+ data: z.object({
+ all_reward: z.object({
+ items: z.array(
+ z.object({
+ redeem_description: z.object({
+ embedded_itemsConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: linkRefsUnionSchema,
+ })
+ ),
+ }),
+ }),
+ system: systemSchema,
+ })
+ ),
+ }),
+ }),
+})
+
+export interface GetRewardWithRedeemRefsSchema
+ extends z.input {}
+
export type CMSReward = z.output[0]
export type CMSRewardWithRedeem = z.output<
diff --git a/server/routers/contentstack/reward/utils.ts b/server/routers/contentstack/reward/utils.ts
index e3309417a..63c850086 100644
--- a/server/routers/contentstack/reward/utils.ts
+++ b/server/routers/contentstack/reward/utils.ts
@@ -4,17 +4,22 @@ import { unstable_cache } from "next/cache"
import { env } from "@/env/server"
import * as api from "@/lib/api"
import { GetRewards } from "@/lib/graphql/Query/Rewards.graphql"
-import { GetRewards as GetRewardsWithReedem } from "@/lib/graphql/Query/RewardsWithRedeem.graphql"
+import {
+ GetRewards as GetRewardsWithReedem,
+ GetRewardsRef as GetRewardsWithRedeemRef,
+} from "@/lib/graphql/Query/RewardsWithRedeem.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
-import { generateLoyaltyConfigTag } from "@/utils/generateTag"
+import { generateLoyaltyConfigTag, generateTag } from "@/utils/generateTag"
import {
type ApiReward,
type CategorizedApiReward,
type CmsRewardsResponse,
type CmsRewardsWithRedeemResponse,
+ type GetRewardWithRedeemRefsSchema,
+ rewardWithRedeemRefsSchema,
validateApiAllTiersSchema,
validateApiTierRewardsSchema,
validateCmsRewardsSchema,
@@ -70,6 +75,16 @@ export const getRedeemSuccessCounter = meter.createCounter(
"trpc.contentstack.reward.redeem-success"
)
+export const getAllCMSRewardRefsCounter = meter.createCounter(
+ "trpc.contentstack.reward.all"
+)
+export const getAllCMSRewardRefsFailCounter = meter.createCounter(
+ "trpc.contentstack.reward.all-fail"
+)
+export const getAllCMSRewardRefsSuccessCounter = meter.createCounter(
+ "trpc.contentstack.reward.all-success"
+)
+
const ONE_HOUR = 60 * 60
export function getUniqueRewardIds(rewardIds: string[]) {
@@ -199,32 +214,100 @@ export const getCachedAllTierRewards = unstable_cache(
{ revalidate: ONE_HOUR }
)
-export async function getCmsRewards(locale: Lang, rewardIds: string[]) {
+export async function getCmsRewards(lang: Lang, rewardIds: string[]) {
const tags = rewardIds.map((id) =>
- generateLoyaltyConfigTag(locale, "reward", id)
+ generateLoyaltyConfigTag(lang, "reward", id)
)
- const cmsRewardsResponse = env.USE_NEW_REWARD_MODEL
- ? await request(
- GetRewardsWithReedem,
- {
- locale: locale,
- rewardIds,
+ let cmsRewardsResponse
+ if (env.USE_NEW_REWARD_MODEL) {
+ getAllCMSRewardRefsCounter.add(1, { lang, rewardIds })
+ console.info(
+ "contentstack.reward.refs start",
+ JSON.stringify({
+ query: { lang, rewardIds },
+ })
+ )
+ const refsResponse = await request(
+ GetRewardsWithRedeemRef,
+ {
+ locale: lang,
+ rewardIds,
+ },
+ {
+ cache: "force-cache",
+ next: {
+ tags: rewardIds.map((rewardId) => generateTag(lang, rewardId)),
},
- { next: { tags }, cache: "force-cache" }
+ }
+ )
+ if (!refsResponse.data) {
+ const notFoundError = notFound(refsResponse)
+ getAllCMSRewardRefsFailCounter.add(1, {
+ lang,
+ rewardIds,
+ error_type: "not_found",
+ error: JSON.stringify({ code: notFoundError.code }),
+ })
+ console.error(
+ "contentstack.reward.refs not found error",
+ JSON.stringify({
+ query: { lang, rewardIds },
+ error: { code: notFoundError.code },
+ })
)
- : await request(
- GetRewards,
- {
- locale: locale,
- rewardIds,
- },
- { next: { tags }, cache: "force-cache" }
+ throw notFoundError
+ }
+
+ const validatedRefsData = rewardWithRedeemRefsSchema.safeParse(refsResponse)
+
+ if (!validatedRefsData.success) {
+ getAllCMSRewardRefsFailCounter.add(1, {
+ lang,
+ rewardIds,
+ error_type: "validation_error",
+ error: JSON.stringify(validatedRefsData.error),
+ })
+ console.error(
+ "contentstack.reward.refs validation error",
+ JSON.stringify({
+ query: { lang, rewardIds },
+ error: validatedRefsData.error,
+ })
)
+ return null
+ }
+
+ getAllCMSRewardRefsSuccessCounter.add(1, { lang, rewardIds })
+ console.info(
+ "contentstack.startPage.refs success",
+ JSON.stringify({
+ query: { lang, rewardIds },
+ })
+ )
+
+ cmsRewardsResponse = await request(
+ GetRewardsWithReedem,
+ {
+ locale: lang,
+ rewardIds,
+ },
+ { next: { tags }, cache: "force-cache" }
+ )
+ } else {
+ cmsRewardsResponse = await request(
+ GetRewards,
+ {
+ locale: lang,
+ rewardIds,
+ },
+ { next: { tags }, cache: "force-cache" }
+ )
+ }
if (!cmsRewardsResponse.data) {
getAllRewardFailCounter.add(1, {
- lang: locale,
+ lang,
error_type: "validation_error",
error: JSON.stringify(cmsRewardsResponse.data),
})
@@ -233,7 +316,7 @@ export async function getCmsRewards(locale: Lang, rewardIds: string[]) {
"contentstack.rewards not found error",
JSON.stringify({
query: {
- locale,
+ locale: lang,
rewardIds,
},
error: { code: notFoundError.code },
@@ -248,7 +331,7 @@ export async function getCmsRewards(locale: Lang, rewardIds: string[]) {
if (!validatedCmsRewards.success) {
getAllRewardFailCounter.add(1, {
- locale,
+ locale: lang,
rewardIds,
error_type: "validation_error",
error: JSON.stringify(validatedCmsRewards.error),
@@ -257,7 +340,7 @@ export async function getCmsRewards(locale: Lang, rewardIds: string[]) {
console.error(
"contentstack.rewards validation error",
JSON.stringify({
- query: { locale, rewardIds },
+ query: { locale: lang, rewardIds },
error: validatedCmsRewards.error,
})
)