Merged in fix/hide-cs-rewards-flag (pull request #1065)

fix: hide new cs rewards model behind feature flag

Approved-by: Michael Zetterberg
Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
Christian Andolf
2024-12-11 08:55:46 +00:00
11 changed files with 105 additions and 22 deletions

View File

@@ -61,3 +61,5 @@ ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH="false"
SHOW_SITE_WIDE_ALERT="false"
SHOW_SIGNUP_FLOW="true"
USE_NEW_REWARDS_ENDPOINT="true"
USE_NEW_REWARD_MODEL="true"

View File

@@ -45,6 +45,7 @@ GOOGLE_DYNAMIC_MAP_ID="test"
HIDE_FOR_NEXT_RELEASE="true"
SALESFORCE_PREFERENCE_BASE_URL="test"
USE_NEW_REWARDS_ENDPOINT="true"
USE_NEW_REWARD_MODEL="true"
TZ=UTC
ENABLE_BOOKING_FLOW="false"

View File

@@ -53,7 +53,7 @@ export default function ClientCurrentRewards({
{reward.label}
</Title>
</div>
{showRedeem && (
{showRedeem && "redeem_description" in reward && (
<div className={styles.btnContainer}>
<Redeem reward={reward} />
</div>

View File

@@ -24,15 +24,15 @@ import { RewardIcon } from "../RewardIcon"
import styles from "./current.module.css"
import type {
Redeem,
RedeemModalState,
RedeemProps,
RedeemStep,
} from "@/types/components/myPages/myPage/accountPage"
const MotionOverlay = motion(ModalOverlay)
const MotionModal = motion(Modal)
export default function Redeem({ reward }: Redeem) {
export default function Redeem({ reward }: RedeemProps) {
const [animation, setAnimation] = useState<RedeemModalState>("unmounted")
const intl = useIntl()
const update = trpc.contentstack.rewards.redeem.useMutation()
@@ -121,9 +121,12 @@ export default function Redeem({ reward }: Redeem) {
<Body textAlign="center">{reward.description}</Body>
)}
{redeemStep === "confirmation" && (
<Body textAlign="center">{reward.redeem_description}</Body>
)}
{redeemStep === "confirmation" &&
"redeem_description" in reward && (
<Body textAlign="center">
{reward.redeem_description}
</Body>
)}
</div>
{redeemStep === "initial" && (
<footer className={styles.modalFooter}>

View File

@@ -26,7 +26,7 @@ export default async function CurrentRewardsBlock({
<ClientCurrentRewards
rewards={rewardsResponse.rewards}
pageSize={6}
showRedeem={env.USE_NEW_REWARDS_ENDPOINT}
showRedeem={env.USE_NEW_REWARDS_ENDPOINT && env.USE_NEW_REWARD_MODEL}
/>
<SectionLink link={link} variant="mobile" />
</SectionContainer>

8
env/server.ts vendored
View File

@@ -115,6 +115,13 @@ export const env = createEnv({
// transform to boolean
.transform((s) => s === "true")
.default("false"),
USE_NEW_REWARD_MODEL: z
.string()
// only allow "true" or "false"
.refine((s) => s === "true" || s === "false")
// transform to boolean
.transform((s) => s === "true")
.default("false"),
},
emptyStringAsUndefined: true,
runtimeEnv: {
@@ -172,6 +179,7 @@ export const env = createEnv({
GOOGLE_DYNAMIC_MAP_ID: process.env.GOOGLE_DYNAMIC_MAP_ID,
HIDE_FOR_NEXT_RELEASE: process.env.HIDE_FOR_NEXT_RELEASE,
USE_NEW_REWARDS_ENDPOINT: process.env.USE_NEW_REWARDS_ENDPOINT,
USE_NEW_REWARD_MODEL: process.env.USE_NEW_REWARD_MODEL,
ENABLE_BOOKING_FLOW: process.env.ENABLE_BOOKING_FLOW,
ENABLE_BOOKING_WIDGET: process.env.ENABLE_BOOKING_WIDGET,
ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH:

View File

@@ -7,7 +7,6 @@ query GetRewards($locale: String!, $rewardIds: [String!]) {
label
grouped_label
description
redeem_description
grouped_description
value
reward_id

View File

@@ -0,0 +1,16 @@
query GetRewards($locale: String!, $rewardIds: [String!]) {
all_reward(locale: $locale, where: { reward_id_in: $rewardIds }) {
items {
taxonomies {
term_uid
}
label
grouped_label
description
redeem_description
grouped_description
value
reward_id
}
}
}

View File

@@ -92,6 +92,30 @@ export const validateApiTierRewardsSchema = z.record(
)
export const validateCmsRewardsSchema = z
.object({
data: z.object({
all_reward: z.object({
items: z.array(
z.object({
taxonomies: z.array(
z.object({
term_uid: z.string().optional(),
})
),
label: z.string().optional(),
reward_id: z.string(),
grouped_label: z.string().optional(),
description: z.string().optional(),
grouped_description: z.string().optional(),
value: z.string().optional(),
})
),
}),
}),
})
.transform((data) => data.data.all_reward.items)
export const validateCmsRewardsWithRedeemSchema = z
.object({
data: z.object({
all_reward: z.object({
@@ -125,12 +149,24 @@ export type SurpriseReward = z.output<typeof SurpriseReward>
export type CmsRewardsResponse = z.input<typeof validateCmsRewardsSchema>
export type CmsRewardsWithRedeemResponse = z.input<
typeof validateCmsRewardsWithRedeemSchema
>
export type CMSReward = z.output<typeof validateCmsRewardsSchema>[0]
export type CMSRewardWithRedeem = z.output<
typeof validateCmsRewardsWithRedeemSchema
>[0]
export type Reward = CMSReward & {
id: string | undefined
}
export type RewardWithRedeem = CMSRewardWithRedeem & {
id: string | undefined
}
// New endpoint related types and schemas.
const BenefitReward = z.object({

View File

@@ -2,8 +2,10 @@ import { metrics } from "@opentelemetry/api"
import { unstable_cache } from "next/cache"
import { Lang } from "@/constants/languages"
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 { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
@@ -11,9 +13,11 @@ import { generateLoyaltyConfigTag } from "@/utils/generateTag"
import {
CmsRewardsResponse,
CmsRewardsWithRedeemResponse,
validateApiAllTiersSchema,
validateApiTierRewardsSchema,
validateCmsRewardsSchema,
validateCmsRewardsWithRedeemSchema,
} from "./output"
const meter = metrics.getMeter("trpc.reward")
@@ -196,14 +200,24 @@ export async function getCmsRewards(locale: Lang, rewardIds: string[]) {
const tags = rewardIds.map((id) =>
generateLoyaltyConfigTag(locale, "reward", id)
)
const cmsRewardsResponse = await request<CmsRewardsResponse>(
GetRewards,
{
locale: locale,
rewardIds,
},
{ next: { tags }, cache: "force-cache" }
)
const cmsRewardsResponse = env.USE_NEW_REWARD_MODEL
? await request<CmsRewardsWithRedeemResponse>(
GetRewardsWithReedem,
{
locale: locale,
rewardIds,
},
{ next: { tags }, cache: "force-cache" }
)
: await request<CmsRewardsResponse>(
GetRewards,
{
locale: locale,
rewardIds,
},
{ next: { tags }, cache: "force-cache" }
)
if (!cmsRewardsResponse.data) {
getAllRewardFailCounter.add(1, {
@@ -225,8 +239,9 @@ export async function getCmsRewards(locale: Lang, rewardIds: string[]) {
throw notFoundError
}
const validatedCmsRewards =
validateCmsRewardsSchema.safeParse(cmsRewardsResponse)
const validatedCmsRewards = env.USE_NEW_REWARD_MODEL
? validateCmsRewardsWithRedeemSchema.safeParse(cmsRewardsResponse)
: validateCmsRewardsSchema.safeParse(cmsRewardsResponse)
if (!validatedCmsRewards.success) {
getAllRewardFailCounter.add(1, {

View File

@@ -1,7 +1,10 @@
import { z } from "zod"
import { blocksSchema } from "@/server/routers/contentstack/accountPage/output"
import { Reward } from "@/server/routers/contentstack/reward/output"
import {
Reward,
RewardWithRedeem,
} from "@/server/routers/contentstack/reward/output"
import { DynamicContent } from "@/types/trpc/routers/contentstack/blocks"
@@ -21,13 +24,13 @@ export type ContentProps = {
}
export interface CurrentRewardsClientProps {
rewards: Reward[]
rewards: (Reward | RewardWithRedeem)[]
pageSize: number
showRedeem: boolean
}
export interface Redeem {
reward: Reward
export interface RedeemProps {
reward: RewardWithRedeem
}
export type RedeemModalState = "unmounted" | "hidden" | "visible"