feat(SW-739): use new allTiers endpoint and add feature flag
This commit is contained in:
@@ -52,3 +52,4 @@ GOOGLE_STATIC_MAP_ID=""
|
|||||||
GOOGLE_DYNAMIC_MAP_ID=""
|
GOOGLE_DYNAMIC_MAP_ID=""
|
||||||
|
|
||||||
HIDE_FOR_NEXT_RELEASE="true"
|
HIDE_FOR_NEXT_RELEASE="true"
|
||||||
|
USE_NEW_REWARDS_ENDPOINT="true"
|
||||||
|
|||||||
@@ -43,3 +43,4 @@ GOOGLE_STATIC_MAP_ID="test"
|
|||||||
GOOGLE_DYNAMIC_MAP_ID="test"
|
GOOGLE_DYNAMIC_MAP_ID="test"
|
||||||
HIDE_FOR_NEXT_RELEASE="true"
|
HIDE_FOR_NEXT_RELEASE="true"
|
||||||
SALESFORCE_PREFERENCE_BASE_URL="test"
|
SALESFORCE_PREFERENCE_BASE_URL="test"
|
||||||
|
USE_NEW_REWARDS_ENDPOINT="true"
|
||||||
|
|||||||
8
env/server.ts
vendored
8
env/server.ts
vendored
@@ -72,6 +72,13 @@ export const env = createEnv({
|
|||||||
.refine((s) => s === "true" || s === "false")
|
.refine((s) => s === "true" || s === "false")
|
||||||
// transform to boolean
|
// transform to boolean
|
||||||
.transform((s) => s === "true"),
|
.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,
|
emptyStringAsUndefined: true,
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
@@ -126,5 +133,6 @@ export const env = createEnv({
|
|||||||
GOOGLE_STATIC_MAP_ID: process.env.GOOGLE_STATIC_MAP_ID,
|
GOOGLE_STATIC_MAP_ID: process.env.GOOGLE_STATIC_MAP_ID,
|
||||||
GOOGLE_DYNAMIC_MAP_ID: process.env.GOOGLE_DYNAMIC_MAP_ID,
|
GOOGLE_DYNAMIC_MAP_ID: process.env.GOOGLE_DYNAMIC_MAP_ID,
|
||||||
HIDE_FOR_NEXT_RELEASE: process.env.HIDE_FOR_NEXT_RELEASE,
|
HIDE_FOR_NEXT_RELEASE: process.env.HIDE_FOR_NEXT_RELEASE,
|
||||||
|
USE_NEW_REWARDS_ENDPOINT: process.env.USE_NEW_REWARDS_ENDPOINT,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -151,8 +151,10 @@ export namespace endpoints {
|
|||||||
export const invalidateSessions = `${base.path.profile}/${version}/${base.enitity.Profile}/invalidateSessions`
|
export const invalidateSessions = `${base.path.profile}/${version}/${base.enitity.Profile}/invalidateSessions`
|
||||||
export const membership = `${base.path.profile}/${version}/${base.enitity.Profile}/membership`
|
export const membership = `${base.path.profile}/${version}/${base.enitity.Profile}/membership`
|
||||||
export const profile = `${base.path.profile}/${version}/${base.enitity.Profile}`
|
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`
|
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 const tierRewards = `${base.path.profile}/${version}/${base.enitity.Profile}/tierRewards`
|
||||||
|
|
||||||
export function deleteProfile(profileId: string) {
|
export function deleteProfile(profileId: string) {
|
||||||
@@ -172,9 +174,11 @@ export namespace endpoints {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export namespace Reward {
|
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 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) {
|
export function claim(rewardId: string) {
|
||||||
return `${base.path.profile}/${version}/${base.enitity.Reward}/Claim/${rewardId}`
|
return `${base.path.profile}/${version}/${base.enitity.Reward}/Claim/${rewardId}`
|
||||||
|
|||||||
@@ -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
|
export const validateCmsRewardsSchema = z
|
||||||
.object({
|
.object({
|
||||||
data: z.object({
|
data: z.object({
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { env } from "@/env/server"
|
||||||
import * as api from "@/lib/api"
|
import * as api from "@/lib/api"
|
||||||
import { notFound } from "@/server/errors/trpc"
|
import { notFound } from "@/server/errors/trpc"
|
||||||
import {
|
import {
|
||||||
@@ -22,6 +23,7 @@ import {
|
|||||||
getByLevelRewardCounter,
|
getByLevelRewardCounter,
|
||||||
getByLevelRewardFailCounter,
|
getByLevelRewardFailCounter,
|
||||||
getByLevelRewardSuccessCounter,
|
getByLevelRewardSuccessCounter,
|
||||||
|
getCachedAllTierRewards,
|
||||||
getCmsRewards,
|
getCmsRewards,
|
||||||
getCurrentRewardCounter,
|
getCurrentRewardCounter,
|
||||||
getCurrentRewardFailCounter,
|
getCurrentRewardFailCounter,
|
||||||
@@ -36,7 +38,10 @@ export const rewardQueryRouter = router({
|
|||||||
.input(rewardsAllInput)
|
.input(rewardsAllInput)
|
||||||
.query(async function ({ input, ctx }) {
|
.query(async function ({ input, ctx }) {
|
||||||
getAllRewardCounter.add(1)
|
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) {
|
if (!allApiRewards) {
|
||||||
return []
|
return []
|
||||||
@@ -96,9 +101,9 @@ export const rewardQueryRouter = router({
|
|||||||
getByLevelRewardCounter.add(1)
|
getByLevelRewardCounter.add(1)
|
||||||
const { level_id } = input
|
const { level_id } = input
|
||||||
|
|
||||||
const allUpcomingApiRewards = await getAllCachedApiRewards(
|
const allUpcomingApiRewards = !!env.USE_NEW_REWARDS_ENDPOINT
|
||||||
ctx.serviceToken
|
? await getCachedAllTierRewards(ctx.serviceToken)
|
||||||
)
|
: await getAllCachedApiRewards(ctx.serviceToken)
|
||||||
|
|
||||||
if (!allUpcomingApiRewards || !allUpcomingApiRewards[level_id]) {
|
if (!allUpcomingApiRewards || !allUpcomingApiRewards[level_id]) {
|
||||||
getByLevelRewardFailCounter.add(1)
|
getByLevelRewardFailCounter.add(1)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { generateLoyaltyConfigTag } from "@/utils/generateTag"
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
CmsRewardsResponse,
|
CmsRewardsResponse,
|
||||||
|
validateApiAllTiersSchema,
|
||||||
validateApiTierRewardsSchema,
|
validateApiTierRewardsSchema,
|
||||||
validateCmsRewardsSchema,
|
validateCmsRewardsSchema,
|
||||||
} from "./output"
|
} 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(
|
export const getAllCachedApiRewards = unstable_cache(
|
||||||
async function (token) {
|
async function (token) {
|
||||||
@@ -110,6 +112,68 @@ export const getAllCachedApiRewards = unstable_cache(
|
|||||||
{ revalidate: ONE_HOUR }
|
{ 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[]) {
|
export async function getCmsRewards(locale: Lang, rewardIds: string[]) {
|
||||||
const tags = rewardIds.map((id) =>
|
const tags = rewardIds.map((id) =>
|
||||||
generateLoyaltyConfigTag(locale, "reward", id)
|
generateLoyaltyConfigTag(locale, "reward", id)
|
||||||
|
|||||||
Reference in New Issue
Block a user