import { cache } from "react" import { type MembershipLevel, MembershipLevelEnum, } from "@/constants/membershipLevels" import { GetAllLoyaltyLevels, GetLoyaltyLevel, } from "@/lib/graphql/Query/LoyaltyLevels.graphql" import { request } from "@/lib/graphql/request" import { notFound } from "@/server/errors/trpc" import { createCounter } from "@/server/telemetry" import { contentstackBaseProcedure, router } from "@/server/trpc" import { generateLoyaltyConfigTag } from "@/utils/generateTag" import { loyaltyLevelInput } from "./input" import { type LoyaltyLevel, type LoyaltyLevelsResponse, validateLoyaltyLevelsSchema, } from "./output" import type { Context } from "@/server/context" export const getAllLoyaltyLevels = cache(async (ctx: Context) => { const getLoyaltyLevelAllCounter = createCounter( "trpc.contentstack", "loyaltyLevel.all" ) const metricsGetLoyaltyLevelAll = getLoyaltyLevelAllCounter.init() metricsGetLoyaltyLevelAll.start() // Ideally we should fetch all available tiers from API, but since they // are static, we can just use the enum values. We want to know which // levels we are fetching so that we can use tags to cache them const allLevelIds = Object.values(MembershipLevelEnum) const tags = allLevelIds.map((levelId) => generateLoyaltyConfigTag(ctx.lang, "loyalty_level", levelId) ) const loyaltyLevelsConfigResponse = await request( GetAllLoyaltyLevels, { lang: ctx.lang, level_ids: allLevelIds }, { key: tags, ttl: "max" } ) if (!loyaltyLevelsConfigResponse.data) { const notFoundError = notFound(loyaltyLevelsConfigResponse) metricsGetLoyaltyLevelAll.noDataError() throw notFoundError } const validatedLoyaltyLevels = validateLoyaltyLevelsSchema.safeParse( loyaltyLevelsConfigResponse.data ) if (!validatedLoyaltyLevels.success) { metricsGetLoyaltyLevelAll.validationError(validatedLoyaltyLevels.error) return [] } metricsGetLoyaltyLevelAll.success() return validatedLoyaltyLevels.data }) export const getLoyaltyLevel = cache( async (ctx: Context, level_id: MembershipLevel) => { const getLoyaltyLevelCounter = createCounter( "trpc.contentstack", "loyaltyLevel.get" ) const metricsGetLoyaltyLevel = getLoyaltyLevelCounter.init({ lang: ctx.lang, level_id, }) metricsGetLoyaltyLevel.start() const loyaltyLevelsConfigResponse = await request( GetLoyaltyLevel, { lang: ctx.lang, level_id }, { key: generateLoyaltyConfigTag(ctx.lang, "loyalty_level", level_id), ttl: "max", } ) if ( !loyaltyLevelsConfigResponse.data || !loyaltyLevelsConfigResponse.data.all_loyalty_level.items.length ) { const notFoundError = notFound(loyaltyLevelsConfigResponse) metricsGetLoyaltyLevel.noDataError() throw notFoundError } const validatedLoyaltyLevels = validateLoyaltyLevelsSchema.safeParse( loyaltyLevelsConfigResponse.data ) if (!validatedLoyaltyLevels.success) { metricsGetLoyaltyLevel.validationError(validatedLoyaltyLevels.error) return null } metricsGetLoyaltyLevel.success() const result: LoyaltyLevel = validatedLoyaltyLevels.data[0] return result } ) export const loyaltyLevelQueryRouter = router({ byLevel: contentstackBaseProcedure .input(loyaltyLevelInput) .query(async function ({ ctx, input }) { return getLoyaltyLevel(ctx, input.level) }), all: contentstackBaseProcedure.query(async function ({ ctx }) { return getAllLoyaltyLevels(ctx) }), })