208 lines
5.4 KiB
TypeScript
208 lines
5.4 KiB
TypeScript
import { z } from "zod"
|
|
|
|
import { MembershipLevelEnum } from "@/constants/membershipLevels"
|
|
import { COUPON_REWARD_TYPES, REWARD_CATEGORIES } from "@/constants/rewards"
|
|
|
|
import {
|
|
linkRefsUnionSchema,
|
|
linkUnionSchema,
|
|
transformPageLink,
|
|
} from "../schemas/pageLinks"
|
|
import { systemSchema } from "../schemas/system"
|
|
|
|
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,
|
|
tier2 = MembershipLevelEnum.L2,
|
|
tier3 = MembershipLevelEnum.L3,
|
|
tier4 = MembershipLevelEnum.L4,
|
|
tier5 = MembershipLevelEnum.L5,
|
|
tier6 = MembershipLevelEnum.L6,
|
|
tier7 = MembershipLevelEnum.L7,
|
|
}
|
|
|
|
type Key = keyof typeof TierKey
|
|
|
|
/*
|
|
* 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({
|
|
items: z.array(
|
|
z.object({
|
|
taxonomies: z.array(
|
|
z.object({
|
|
term_uid: z.string().optional().default(""),
|
|
})
|
|
),
|
|
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)
|
|
|
|
type CMSRewardsResponse = z.input<typeof validateCmsRewardsSchema>
|
|
type CMSReward = z.output<typeof validateCmsRewardsSchema>[number]
|
|
|
|
const validateCmsRewardsWithRedeemSchema = z
|
|
.object({
|
|
data: z.object({
|
|
all_reward: z.object({
|
|
items: z.array(
|
|
z.object({
|
|
taxonomies: z.array(
|
|
z.object({
|
|
term_uid: z.string().optional().default(""),
|
|
})
|
|
),
|
|
label: z.string().optional(),
|
|
reward_id: z.string(),
|
|
grouped_label: z.string().optional(),
|
|
description: z.string().optional(),
|
|
redeem_description: z.object({
|
|
json: z.any(), // JSON
|
|
embedded_itemsConnection: z.object({
|
|
edges: z.array(
|
|
z.object({
|
|
node: linkUnionSchema.transform((data) => {
|
|
const link = transformPageLink(data)
|
|
if (link) {
|
|
return link
|
|
}
|
|
return data
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
}),
|
|
grouped_description: z.string().optional(),
|
|
value: z.string().optional(),
|
|
})
|
|
),
|
|
}),
|
|
}),
|
|
})
|
|
.transform((data) => data.data.all_reward.items)
|
|
|
|
type CMSRewardsWithRedeemResponse = z.input<
|
|
typeof validateCmsRewardsWithRedeemSchema
|
|
>
|
|
type CMSRewardWithRedeem = z.output<
|
|
typeof validateCmsRewardsWithRedeemSchema
|
|
>[number]
|
|
|
|
const rewardWithRedeemRefsSchema = z.object({
|
|
data: z.object({
|
|
all_reward: z.object({
|
|
items: z.array(
|
|
z.object({
|
|
redeem_description: z.object({
|
|
embedded_itemsConnection: z.object({
|
|
edges: z.array(
|
|
z.object({
|
|
node: linkRefsUnionSchema,
|
|
})
|
|
),
|
|
}),
|
|
}),
|
|
system: systemSchema,
|
|
})
|
|
),
|
|
}),
|
|
}),
|
|
})
|
|
|
|
type GetRewardWithRedeemRefsSchema = z.input<typeof rewardWithRedeemRefsSchema>
|
|
|
|
const REDEEM_LOCATIONS = ["Non-redeemable", "On-site", "Online"] as const
|
|
type RedeemLocation = (typeof REDEEM_LOCATIONS)[number]
|
|
|
|
const BaseReward = z.object({
|
|
title: 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.enum(["Tier"]),
|
|
rewardTierLevel: z.string().optional(),
|
|
})
|
|
)
|
|
|
|
const CouponData = z.object({
|
|
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({
|
|
rewardType: z.enum(COUPON_REWARD_TYPES),
|
|
operaRewardId: z.string().default(""),
|
|
categories: z.array(z.enum(REWARD_CATEGORIES)).optional(),
|
|
coupon: z
|
|
.array(CouponData)
|
|
.optional()
|
|
.transform((val) => val || []),
|
|
})
|
|
)
|
|
|
|
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, ...data.coupons])
|
|
|
|
type ApiReward = z.output<typeof validateCategorizedRewardsSchema>[number]
|
|
|
|
const validateApiAllTiersSchema = z.record(
|
|
z.nativeEnum(TierKey).transform((data) => {
|
|
return TierKey[data as unknown as Key]
|
|
}),
|
|
z.array(BenefitReward)
|
|
)
|