Feat(SW-3708): refactor contentstack fetching (removing all refs) and cache invalidation * Remove all REFS * Revalidate correct language * PR fixes * PR fixes * Throw when errors from contentstack api Approved-by: Joakim Jäderberg
145 lines
3.8 KiB
TypeScript
145 lines
3.8 KiB
TypeScript
import { z } from "zod"
|
|
|
|
import { MembershipLevelEnum } from "@scandic-hotels/common/constants/membershipLevels"
|
|
|
|
import { linkUnionSchema, transformPageLink } from "../schemas/pageLinks"
|
|
|
|
export {
|
|
BenefitReward,
|
|
CouponData,
|
|
CouponReward,
|
|
REDEEM_LOCATIONS,
|
|
REWARD_TYPES,
|
|
validateApiAllTiersSchema,
|
|
validateCategorizedRewardsSchema,
|
|
validateCmsRewardsSchema,
|
|
}
|
|
|
|
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(),
|
|
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
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
// This is primarily added in order to handle a transition
|
|
// switching from string to RTE
|
|
.nullable(),
|
|
grouped_description: z.string().optional(),
|
|
value: z.string().optional(),
|
|
})
|
|
),
|
|
}),
|
|
}),
|
|
})
|
|
.transform((data) => data.data.all_reward.items)
|
|
|
|
const REDEEM_LOCATIONS = ["Non-redeemable", "On-site", "Online"] as const
|
|
const REWARD_CATEGORIES = [
|
|
"Restaurants",
|
|
"Bar",
|
|
"Voucher",
|
|
"Services and rooms",
|
|
"Spa and gym",
|
|
] as const
|
|
|
|
const BaseReward = z.object({
|
|
title: z.string().optional(),
|
|
id: z.string(),
|
|
categories: z
|
|
.array(z.enum(REWARD_CATEGORIES).or(z.literal("")))
|
|
.optional()
|
|
// we sometimes receive empty categories, this filters them out
|
|
.transform((categories = []) =>
|
|
categories.filter(
|
|
(c): c is (typeof REWARD_CATEGORIES)[number] => c !== ""
|
|
)
|
|
),
|
|
rewardId: z.string(),
|
|
redeemLocation: z.enum(REDEEM_LOCATIONS),
|
|
status: z.enum(["active", "expired"]),
|
|
})
|
|
|
|
const REWARD_TYPES = {
|
|
Surprise: "Surprise",
|
|
Campaign: "Campaign",
|
|
MemberVoucher: "Member-voucher",
|
|
Tier: "Tier",
|
|
} as const
|
|
|
|
const BenefitReward = BaseReward.merge(
|
|
z.object({
|
|
rewardType: z.enum([REWARD_TYPES.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(),
|
|
})
|
|
|
|
const CouponReward = BaseReward.merge(
|
|
z.object({
|
|
rewardType: z.enum([
|
|
REWARD_TYPES.Surprise,
|
|
REWARD_TYPES.Campaign,
|
|
REWARD_TYPES.MemberVoucher,
|
|
]),
|
|
operaRewardId: z.string().default(""),
|
|
coupon: z
|
|
.array(CouponData)
|
|
.optional()
|
|
.transform((val) => val || []),
|
|
})
|
|
)
|
|
|
|
const validateCategorizedRewardsSchema = z.object({
|
|
benefits: z.array(BenefitReward),
|
|
coupons: z.array(CouponReward),
|
|
})
|
|
|
|
const TierKeyMapping = {
|
|
tier1: MembershipLevelEnum.L1,
|
|
tier2: MembershipLevelEnum.L2,
|
|
tier3: MembershipLevelEnum.L3,
|
|
tier4: MembershipLevelEnum.L4,
|
|
tier5: MembershipLevelEnum.L5,
|
|
tier6: MembershipLevelEnum.L6,
|
|
tier7: MembershipLevelEnum.L7,
|
|
} as const
|
|
|
|
const TierKeys = Object.keys(TierKeyMapping) as [keyof typeof TierKeyMapping]
|
|
|
|
const validateApiAllTiersSchema = z.record(
|
|
z.enum(TierKeys).transform((data) => TierKeyMapping[data]),
|
|
z.array(BenefitReward)
|
|
)
|