refactor(LOY-175): rewrite reward types according to new api endpoints
This commit is contained in:
@@ -10,7 +10,24 @@ import {
|
||||
} from "../schemas/pageLinks"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
import type { RewardCategory } from "@/types/components/myPages/rewards"
|
||||
export {
|
||||
type ApiReward,
|
||||
type CMSReward,
|
||||
type CMSRewardsResponse,
|
||||
type CMSRewardsWithRedeemResponse,
|
||||
type CMSRewardWithRedeem,
|
||||
type Coupon,
|
||||
type GetRewardWithRedeemRefsSchema,
|
||||
type RedeemableCoupon,
|
||||
type RedeemLocation,
|
||||
rewardWithRedeemRefsSchema,
|
||||
type Surprise,
|
||||
type SurpriseReward,
|
||||
validateApiAllTiersSchema,
|
||||
validateCategorizedRewardsSchema,
|
||||
validateCmsRewardsSchema,
|
||||
validateCmsRewardsWithRedeemSchema,
|
||||
}
|
||||
|
||||
enum TierKey {
|
||||
tier1 = MembershipLevelEnum.L1,
|
||||
@@ -24,7 +41,10 @@ enum TierKey {
|
||||
|
||||
type Key = keyof typeof TierKey
|
||||
|
||||
export const validateCmsRewardsSchema = z
|
||||
/*
|
||||
* TODO: Remove this once we start using the new CMS model with redeem entirely
|
||||
*/
|
||||
const validateCmsRewardsSchema = z
|
||||
.object({
|
||||
data: z.object({
|
||||
all_reward: z.object({
|
||||
@@ -48,7 +68,10 @@ export const validateCmsRewardsSchema = z
|
||||
})
|
||||
.transform((data) => data.data.all_reward.items)
|
||||
|
||||
export const validateCmsRewardsWithRedeemSchema = z
|
||||
type CMSRewardsResponse = z.input<typeof validateCmsRewardsSchema>
|
||||
type CMSReward = z.output<typeof validateCmsRewardsSchema>[number]
|
||||
|
||||
const validateCmsRewardsWithRedeemSchema = z
|
||||
.object({
|
||||
data: z.object({
|
||||
all_reward: z.object({
|
||||
@@ -88,13 +111,14 @@ export const validateCmsRewardsWithRedeemSchema = z
|
||||
})
|
||||
.transform((data) => data.data.all_reward.items)
|
||||
|
||||
export type CmsRewardsResponse = z.input<typeof validateCmsRewardsSchema>
|
||||
|
||||
export type CmsRewardsWithRedeemResponse = z.input<
|
||||
type CMSRewardsWithRedeemResponse = z.input<
|
||||
typeof validateCmsRewardsWithRedeemSchema
|
||||
>
|
||||
type CMSRewardWithRedeem = z.output<
|
||||
typeof validateCmsRewardsWithRedeemSchema
|
||||
>[number]
|
||||
|
||||
export const rewardWithRedeemRefsSchema = z.object({
|
||||
const rewardWithRedeemRefsSchema = z.object({
|
||||
data: z.object({
|
||||
all_reward: z.object({
|
||||
items: z.array(
|
||||
@@ -115,70 +139,36 @@ export const rewardWithRedeemRefsSchema = z.object({
|
||||
}),
|
||||
})
|
||||
|
||||
export interface GetRewardWithRedeemRefsSchema
|
||||
extends z.input<typeof rewardWithRedeemRefsSchema> {}
|
||||
type GetRewardWithRedeemRefsSchema = z.input<typeof rewardWithRedeemRefsSchema>
|
||||
|
||||
export type CMSReward = z.output<typeof validateCmsRewardsSchema>[0]
|
||||
const REDEEM_LOCATIONS = ["Non-redeemable", "On-site", "Online"] as const
|
||||
type RedeemLocation = (typeof REDEEM_LOCATIONS)[number]
|
||||
|
||||
export type CMSRewardWithRedeem = z.output<
|
||||
typeof validateCmsRewardsWithRedeemSchema
|
||||
>[0]
|
||||
|
||||
export type Reward = CMSReward & {
|
||||
id: string | undefined
|
||||
rewardType: string | undefined
|
||||
redeemLocation: string | undefined
|
||||
rewardTierLevel: string | undefined
|
||||
operaRewardId: string
|
||||
categories: RewardCategory[]
|
||||
couponCode: string | undefined
|
||||
coupons: Coupon[]
|
||||
}
|
||||
|
||||
export type RewardWithRedeem = CMSRewardWithRedeem & {
|
||||
id: string | undefined
|
||||
rewardType: string | undefined
|
||||
redeemLocation: string | undefined
|
||||
rewardTierLevel: string | undefined
|
||||
operaRewardId: string
|
||||
categories: RewardCategory[]
|
||||
couponCode: string | undefined
|
||||
coupons: Coupon[]
|
||||
}
|
||||
|
||||
export interface Coupon {
|
||||
couponCode?: string
|
||||
expiresAt?: string
|
||||
unwrapped: boolean
|
||||
state: "claimed" | "redeemed" | "viewed"
|
||||
}
|
||||
|
||||
export interface Surprise extends Omit<Reward, "operaRewardId" | "couponCode"> {
|
||||
coupons: Coupon[]
|
||||
}
|
||||
|
||||
// New endpoint related types and schemas.
|
||||
const BaseReward = z.object({
|
||||
title: z.string().optional(),
|
||||
id: z.string().optional(),
|
||||
rewardId: z.string().optional(),
|
||||
redeemLocation: z.string().optional(),
|
||||
status: z.string().optional(),
|
||||
id: z.string(),
|
||||
rewardId: z.string(),
|
||||
redeemLocation: z.enum(REDEEM_LOCATIONS),
|
||||
status: z.enum(["active", "expired"]),
|
||||
})
|
||||
|
||||
const BenefitReward = BaseReward.merge(
|
||||
z.object({
|
||||
rewardType: z.string().optional(), // TODO: Should be "Tier" but can't because of backwards compatibility
|
||||
rewardType: z.enum(["Tier"]),
|
||||
rewardTierLevel: z.string().optional(),
|
||||
})
|
||||
)
|
||||
|
||||
const CouponData = z.object({
|
||||
couponCode: z.string().optional(),
|
||||
couponCode: z.string(),
|
||||
unwrapped: z.boolean().default(false),
|
||||
state: z.enum(["claimed", "redeemed", "viewed"]),
|
||||
expiresAt: z.string().datetime({ offset: true }).optional(),
|
||||
})
|
||||
type Coupon = z.output<typeof CouponData>
|
||||
type RedeemableCoupon = Coupon & {
|
||||
state: Exclude<Coupon["state"], "redeemed">
|
||||
}
|
||||
|
||||
const CouponReward = BaseReward.merge(
|
||||
z.object({
|
||||
@@ -192,38 +182,26 @@ const CouponReward = BaseReward.merge(
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* 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
|
||||
type SurpriseReward = z.output<typeof CouponReward> & {
|
||||
rewardType: "Surprise"
|
||||
}
|
||||
|
||||
interface Surprise extends CMSReward {
|
||||
data: SurpriseReward
|
||||
}
|
||||
|
||||
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.
|
||||
})),
|
||||
])
|
||||
.transform((data) => [...data.benefits, ...data.coupons])
|
||||
|
||||
export type CategorizedApiReward = z.output<
|
||||
typeof validateCategorizedRewardsSchema
|
||||
>[number]
|
||||
type ApiReward = z.output<typeof validateCategorizedRewardsSchema>[number]
|
||||
|
||||
export const validateApiAllTiersSchema = z.record(
|
||||
const validateApiAllTiersSchema = z.record(
|
||||
z.nativeEnum(TierKey).transform((data) => {
|
||||
return TierKey[data as unknown as Key]
|
||||
}),
|
||||
z.array(BenefitReward)
|
||||
)
|
||||
|
||||
export type RedeemLocation = "Non-redeemable" | "On-site" | "Online"
|
||||
|
||||
Reference in New Issue
Block a user