feat: update current & surprise queries to support new endpoint

This commit is contained in:
Chuma McPhoy
2024-11-12 14:28:52 +01:00
parent 48af26a772
commit 31a94cfa6a
3 changed files with 89 additions and 28 deletions

View File

@@ -91,22 +91,6 @@ 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({
@@ -138,3 +122,61 @@ export type SurpriseReward = z.output<typeof SurpriseReward>
export type CmsRewardsResponse = z.input<typeof validateCmsRewardsSchema> export type CmsRewardsResponse = z.input<typeof validateCmsRewardsSchema>
export type Reward = z.output<typeof validateCmsRewardsSchema>[0] export type Reward = z.output<typeof validateCmsRewardsSchema>[0]
// New endpoint related types and schemas.
const BenefitReward = z.object({
title: z.string().optional(),
id: z.string().optional(),
status: z.string().optional(),
rewardId: z.string().optional(),
rewardType: z.string().optional(),
rewardTierLevel: z.string().optional(),
})
const CouponState = z.enum(["claimed", "redeemed", "viewed"])
const CouponData = z.object({
couponCode: z.string().optional(),
unwrapped: z.boolean().default(false),
state: CouponState,
expiresAt: z.string().datetime({ offset: true }).optional(),
})
const CouponReward = z.object({
title: z.string().optional(),
id: z.string().optional(),
rewardId: z.string().optional(),
rewardType: z.string().optional(),
status: z.string().optional(),
coupon: z.array(CouponData).optional(),
})
/**
* Schema for the new /profile/v1/Reward endpoint.
*
* TODO: Once we fully migrate to the new endpoint:
* 1. Remove the data transform and use the categorized structure directly.
* 2. Simplify surprise filtering in the query.
*/
export const validateCategorizedRewardsSchema = z
.object({
benefits: z.array(BenefitReward),
coupons: z.array(CouponReward),
})
.transform((data) => [
...data.benefits.map((benefit) => ({
...benefit,
type: "custom" as const, // Added for legacy compatibility.
})),
...data.coupons.map((coupon) => ({
...coupon,
type: "coupon" as const, // Added for legacy compatibility.
})),
])
export const validateApiAllTiersSchema = z.record(
z.nativeEnum(TierKey).transform((data) => {
return TierKey[data as unknown as Key]
}),
z.array(BenefitReward)
)

View File

@@ -14,7 +14,12 @@ import {
rewardsCurrentInput, rewardsCurrentInput,
rewardsUpdateInput, rewardsUpdateInput,
} from "./input" } from "./input"
import { Reward, SurpriseReward, validateApiRewardSchema } from "./output" import {
Reward,
SurpriseReward,
validateApiRewardSchema,
validateCategorizedRewardsSchema,
} from "./output"
import { import {
getAllCachedApiRewards, getAllCachedApiRewards,
getAllRewardCounter, getAllRewardCounter,
@@ -33,6 +38,8 @@ import {
import { Surprise } from "@/types/components/blocks/surprises" import { Surprise } from "@/types/components/blocks/surprises"
const ONE_HOUR = 60 * 60
export const rewardQueryRouter = router({ export const rewardQueryRouter = router({
all: contentStackBaseWithServiceProcedure all: contentStackBaseWithServiceProcedure
.input(rewardsAllInput) .input(rewardsAllInput)
@@ -154,12 +161,17 @@ export const rewardQueryRouter = router({
const { limit, cursor } = input const { limit, cursor } = input
const apiResponse = await api.get(api.endpoints.v1.Profile.reward, { const isNewEndpoint = !!env.USE_NEW_REWARDS_ENDPOINT
const endpoint = isNewEndpoint
? api.endpoints.v1.Profile.Reward.reward
: api.endpoints.v1.Profile.reward
const apiResponse = await api.get(endpoint, {
cache: undefined, // override defaultOptions cache: undefined, // override defaultOptions
headers: { headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`, Authorization: `Bearer ${ctx.session.token.access_token}`,
}, },
next: { revalidate: 60 * 60 }, next: { revalidate: ONE_HOUR },
}) })
if (!apiResponse.ok) { if (!apiResponse.ok) {
@@ -186,8 +198,9 @@ export const rewardQueryRouter = router({
} }
const data = await apiResponse.json() const data = await apiResponse.json()
const validatedApiRewards = isNewEndpoint
const validatedApiRewards = validateApiRewardSchema.safeParse(data) ? validateCategorizedRewardsSchema.safeParse(data)
: validateApiRewardSchema.safeParse(data)
if (!validatedApiRewards.success) { if (!validatedApiRewards.success) {
getCurrentRewardFailCounter.add(1, { getCurrentRewardFailCounter.add(1, {
@@ -243,12 +256,17 @@ export const rewardQueryRouter = router({
surprises: contentStackBaseWithProtectedProcedure.query(async ({ ctx }) => { surprises: contentStackBaseWithProtectedProcedure.query(async ({ ctx }) => {
getCurrentRewardCounter.add(1) getCurrentRewardCounter.add(1)
const apiResponse = await api.get(api.endpoints.v1.Profile.reward, { const isNewEndpoint = !!env.USE_NEW_REWARDS_ENDPOINT
cache: undefined, // override defaultOptions const endpoint = isNewEndpoint
? api.endpoints.v1.Profile.Reward.reward
: api.endpoints.v1.Profile.reward
const apiResponse = await api.get(endpoint, {
cache: undefined,
headers: { headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`, Authorization: `Bearer ${ctx.session.token.access_token}`,
}, },
next: { revalidate: 60 * 60 }, next: { revalidate: ONE_HOUR },
}) })
if (!apiResponse.ok) { if (!apiResponse.ok) {
@@ -275,8 +293,9 @@ export const rewardQueryRouter = router({
} }
const data = await apiResponse.json() const data = await apiResponse.json()
const validatedApiRewards = isNewEndpoint
const validatedApiRewards = validateApiRewardSchema.safeParse(data) ? validateCategorizedRewardsSchema.safeParse(data)
: validateApiRewardSchema.safeParse(data)
if (!validatedApiRewards.success) { if (!validatedApiRewards.success) {
getCurrentRewardFailCounter.add(1, { getCurrentRewardFailCounter.add(1, {

View File

@@ -53,8 +53,8 @@ export function getUniqueRewardIds(rewardIds: string[]) {
} }
/** /**
* Uses profile/v1/Profile/tierRewards. * Uses the legacy profile/v1/Profile/tierRewards endpoint.
* Will be removed when new endpoint is out in production. * TODO: Delete when the new endpoint is out in production.
*/ */
export const getAllCachedApiRewards = unstable_cache( export const getAllCachedApiRewards = unstable_cache(
async function (token) { async function (token) {