feat(SW-739): use new allTiers endpoint and add feature flag

This commit is contained in:
Chuma McPhoy
2024-11-08 14:50:18 +01:00
parent 35a527be05
commit 48af26a772
7 changed files with 107 additions and 8 deletions

View File

@@ -52,3 +52,4 @@ GOOGLE_STATIC_MAP_ID=""
GOOGLE_DYNAMIC_MAP_ID=""
HIDE_FOR_NEXT_RELEASE="true"
USE_NEW_REWARDS_ENDPOINT="true"

View File

@@ -43,3 +43,4 @@ GOOGLE_STATIC_MAP_ID="test"
GOOGLE_DYNAMIC_MAP_ID="test"
HIDE_FOR_NEXT_RELEASE="true"
SALESFORCE_PREFERENCE_BASE_URL="test"
USE_NEW_REWARDS_ENDPOINT="true"

8
env/server.ts vendored
View File

@@ -72,6 +72,13 @@ export const env = createEnv({
.refine((s) => s === "true" || s === "false")
// transform to boolean
.transform((s) => s === "true"),
USE_NEW_REWARDS_ENDPOINT: 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: {
@@ -126,5 +133,6 @@ export const env = createEnv({
GOOGLE_STATIC_MAP_ID: process.env.GOOGLE_STATIC_MAP_ID,
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,
},
})

View File

@@ -151,8 +151,10 @@ export namespace endpoints {
export const invalidateSessions = `${base.path.profile}/${version}/${base.enitity.Profile}/invalidateSessions`
export const membership = `${base.path.profile}/${version}/${base.enitity.Profile}/membership`
export const profile = `${base.path.profile}/${version}/${base.enitity.Profile}`
export const reward = `${base.path.profile}/${version}/${base.enitity.Profile}/reward`
export const subscriberId = `${base.path.profile}/${version}/${base.enitity.Profile}/SubscriberId`
// TODO: Remove once new endpoints are out in production.
export const reward = `${base.path.profile}/${version}/${base.enitity.Profile}/reward`
export const tierRewards = `${base.path.profile}/${version}/${base.enitity.Profile}/tierRewards`
export function deleteProfile(profileId: string) {
@@ -172,9 +174,11 @@ export namespace endpoints {
}
export namespace Reward {
export const allTiers = `${base.path.profile}/${version}/${base.enitity.Reward}/AllTiers`
export const allTiers = `${base.path.profile}/${version}/${base.enitity.Reward}/allTiers`
export const reward = `${base.path.profile}/${version}/${base.enitity.Reward}`
export const unwrap = `${base.path.profile}/${version}/${base.enitity.Reward}/Unwrap`
export const redeem = `${base.path.profile}/${version}/${base.enitity.Reward}/redeem`
export const unwrap = `${base.path.profile}/${version}/${base.enitity.Reward}/unwrap`
// TODO: add surprise endpoint once available.
export function claim(rewardId: string) {
return `${base.path.profile}/${version}/${base.enitity.Reward}/Claim/${rewardId}`

View File

@@ -91,6 +91,22 @@ export const validateApiTierRewardsSchema = z.record(
)
)
export const validateApiAllTiersSchema = z.record(
z.nativeEnum(TierKey).transform((data) => {
return TierKey[data as unknown as Key]
}),
z.array(
z.object({
id: z.string().optional(),
status: z.string().optional(),
rewardId: z.string().optional(),
rewardTierLevel: z.string().optional(),
rewardType: z.string().optional(),
title: z.string().optional(),
})
)
)
export const validateCmsRewardsSchema = z
.object({
data: z.object({

View File

@@ -1,3 +1,4 @@
import { env } from "@/env/server"
import * as api from "@/lib/api"
import { notFound } from "@/server/errors/trpc"
import {
@@ -22,6 +23,7 @@ import {
getByLevelRewardCounter,
getByLevelRewardFailCounter,
getByLevelRewardSuccessCounter,
getCachedAllTierRewards,
getCmsRewards,
getCurrentRewardCounter,
getCurrentRewardFailCounter,
@@ -36,7 +38,10 @@ export const rewardQueryRouter = router({
.input(rewardsAllInput)
.query(async function ({ input, ctx }) {
getAllRewardCounter.add(1)
const allApiRewards = await getAllCachedApiRewards(ctx.serviceToken)
const allApiRewards = !!env.USE_NEW_REWARDS_ENDPOINT
? await getCachedAllTierRewards(ctx.serviceToken)
: await getAllCachedApiRewards(ctx.serviceToken)
if (!allApiRewards) {
return []
@@ -96,9 +101,9 @@ export const rewardQueryRouter = router({
getByLevelRewardCounter.add(1)
const { level_id } = input
const allUpcomingApiRewards = await getAllCachedApiRewards(
ctx.serviceToken
)
const allUpcomingApiRewards = !!env.USE_NEW_REWARDS_ENDPOINT
? await getCachedAllTierRewards(ctx.serviceToken)
: await getAllCachedApiRewards(ctx.serviceToken)
if (!allUpcomingApiRewards || !allUpcomingApiRewards[level_id]) {
getByLevelRewardFailCounter.add(1)

View File

@@ -11,6 +11,7 @@ import { generateLoyaltyConfigTag } from "@/utils/generateTag"
import {
CmsRewardsResponse,
validateApiAllTiersSchema,
validateApiTierRewardsSchema,
validateCmsRewardsSchema,
} from "./output"
@@ -52,7 +53,8 @@ export function getUniqueRewardIds(rewardIds: string[]) {
}
/**
* Cached for 1 hour.
* Uses profile/v1/Profile/tierRewards.
* Will be removed when new endpoint is out in production.
*/
export const getAllCachedApiRewards = unstable_cache(
async function (token) {
@@ -110,6 +112,68 @@ export const getAllCachedApiRewards = unstable_cache(
{ revalidate: ONE_HOUR }
)
/**
* Cached for 1 hour.
*/
export const getCachedAllTierRewards = unstable_cache(
async function (token) {
const apiResponse = await api.get(
api.endpoints.v1.Profile.Reward.allTiers,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
)
if (!apiResponse.ok) {
const text = await apiResponse.text()
getAllRewardFailCounter.add(1, {
error_type: "http_error",
error: JSON.stringify({
status: apiResponse.status,
statusText: apiResponse.statusText,
text,
}),
})
console.error(
"api.rewards.allTiers error ",
JSON.stringify({
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text,
},
})
)
throw apiResponse
}
const data = await apiResponse.json()
const validatedApiAllTierRewards = validateApiAllTiersSchema.safeParse(data)
if (!validatedApiAllTierRewards.success) {
getAllRewardFailCounter.add(1, {
error_type: "validation_error",
error: JSON.stringify(validatedApiAllTierRewards.error),
})
console.error(validatedApiAllTierRewards.error)
console.error(
"api.rewards validation error",
JSON.stringify({
error: validatedApiAllTierRewards.error,
})
)
throw validatedApiAllTierRewards.error
}
return validatedApiAllTierRewards.data
},
["getApiAllTierRewards"],
{ revalidate: ONE_HOUR }
)
export async function getCmsRewards(locale: Lang, rewardIds: string[]) {
const tags = rewardIds.map((id) =>
generateLoyaltyConfigTag(locale, "reward", id)