feat(LOY-64): add ActiveRedeemedBadge UI for on site tier rewards
This commit is contained in:
@@ -17,6 +17,7 @@ export default function ClientCurrentRewards({
|
|||||||
rewards,
|
rewards,
|
||||||
pageSize,
|
pageSize,
|
||||||
showRedeem,
|
showRedeem,
|
||||||
|
memberId,
|
||||||
}: CurrentRewardsClientProps) {
|
}: CurrentRewardsClientProps) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
const [currentPage, setCurrentPage] = useState(1)
|
const [currentPage, setCurrentPage] = useState(1)
|
||||||
@@ -55,7 +56,7 @@ export default function ClientCurrentRewards({
|
|||||||
</div>
|
</div>
|
||||||
{showRedeem && "redeem_description" in reward && (
|
{showRedeem && "redeem_description" in reward && (
|
||||||
<div className={styles.btnContainer}>
|
<div className={styles.btnContainer}>
|
||||||
<Redeem reward={reward} />
|
<Redeem reward={reward} memberId={memberId} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { motion } from "framer-motion"
|
import { AnimatePresence, motion } from "framer-motion"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { trpc } from "@/lib/trpc/client"
|
import { trpc } from "@/lib/trpc/client"
|
||||||
|
import { Reward } from "@/server/routers/contentstack/reward/output"
|
||||||
|
|
||||||
import Countdown from "@/components/Countdown"
|
import Countdown from "@/components/Countdown"
|
||||||
import { CheckCircleIcon, CloseLargeIcon } from "@/components/Icons"
|
import { CheckCircleIcon, CloseLargeIcon } from "@/components/Icons"
|
||||||
@@ -18,6 +19,7 @@ import Button from "@/components/TempDesignSystem/Button"
|
|||||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||||
|
import { isRestaurantOnSiteTierReward } from "@/utils/rewards"
|
||||||
|
|
||||||
import { RewardIcon } from "../RewardIcon"
|
import { RewardIcon } from "../RewardIcon"
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ import type {
|
|||||||
const MotionOverlay = motion(ModalOverlay)
|
const MotionOverlay = motion(ModalOverlay)
|
||||||
const MotionModal = motion(Modal)
|
const MotionModal = motion(Modal)
|
||||||
|
|
||||||
export default function Redeem({ reward }: RedeemProps) {
|
export default function Redeem({ reward, memberId }: RedeemProps) {
|
||||||
const [animation, setAnimation] = useState<RedeemModalState>("unmounted")
|
const [animation, setAnimation] = useState<RedeemModalState>("unmounted")
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const update = trpc.contentstack.rewards.redeem.useMutation()
|
const update = trpc.contentstack.rewards.redeem.useMutation()
|
||||||
@@ -100,17 +102,7 @@ export default function Redeem({ reward }: RedeemProps) {
|
|||||||
</header>
|
</header>
|
||||||
<div className={styles.modalContent}>
|
<div className={styles.modalContent}>
|
||||||
{redeemStep === "redeemed" && (
|
{redeemStep === "redeemed" && (
|
||||||
<div className={styles.badge}>
|
<ConfirmationBadge reward={reward} />
|
||||||
<div className={styles.redeemed}>
|
|
||||||
<CheckCircleIcon color="uiSemanticSuccess" />
|
|
||||||
<Caption>
|
|
||||||
{intl.formatMessage({
|
|
||||||
id: "Redeemed & valid through:",
|
|
||||||
})}
|
|
||||||
</Caption>
|
|
||||||
</div>
|
|
||||||
<Countdown />
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
<RewardIcon rewardId={reward.reward_id} />
|
<RewardIcon rewardId={reward.reward_id} />
|
||||||
<Title level="h3" textAlign="center" textTransform="regular">
|
<Title level="h3" textAlign="center" textTransform="regular">
|
||||||
@@ -127,6 +119,18 @@ export default function Redeem({ reward }: RedeemProps) {
|
|||||||
{reward.redeem_description}
|
{reward.redeem_description}
|
||||||
</Body>
|
</Body>
|
||||||
)}
|
)}
|
||||||
|
{redeemStep === "redeemed" &&
|
||||||
|
isRestaurantOnSiteTierReward(reward) && (
|
||||||
|
<div className={styles.memberIdBadge}>
|
||||||
|
<Caption
|
||||||
|
textTransform="uppercase"
|
||||||
|
textAlign="center"
|
||||||
|
color="uiTextHighContrast"
|
||||||
|
>
|
||||||
|
{intl.formatMessage({ id: "Member ID:" })} {memberId}
|
||||||
|
</Caption>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{redeemStep === "initial" && (
|
{redeemStep === "initial" && (
|
||||||
<footer className={styles.modalFooter}>
|
<footer className={styles.modalFooter}>
|
||||||
@@ -189,3 +193,55 @@ const variants = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ConfirmationBadge({ reward }: { reward: Reward }) {
|
||||||
|
return (
|
||||||
|
<div className={styles.badge}>
|
||||||
|
{isRestaurantOnSiteTierReward(reward) ? (
|
||||||
|
<ActiveRedeemedBadge />
|
||||||
|
) : (
|
||||||
|
<TimedRedeemedBadge />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ActiveRedeemedBadge() {
|
||||||
|
const intl = useIntl()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.redeemed}>
|
||||||
|
<motion.div
|
||||||
|
animate={{
|
||||||
|
opacity: [1, 0.4, 1],
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
duration: 2,
|
||||||
|
repeat: Infinity,
|
||||||
|
ease: "easeInOut",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CheckCircleIcon color="uiSemanticSuccess" />
|
||||||
|
</motion.div>
|
||||||
|
<Caption>{intl.formatMessage({ id: "Active" })}</Caption>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TimedRedeemedBadge() {
|
||||||
|
const intl = useIntl()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.redeemed}>
|
||||||
|
<CheckCircleIcon color="uiSemanticSuccess" />
|
||||||
|
<Caption>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "Redeemed & valid through:",
|
||||||
|
})}
|
||||||
|
</Caption>
|
||||||
|
</div>
|
||||||
|
<Countdown />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
min-height: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.redeemed {
|
.redeemed {
|
||||||
@@ -130,3 +131,16 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--Spacing-x-half);
|
||||||
|
color: var(--UI-Semantic-Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberIdBadge {
|
||||||
|
border-radius: var(--Small);
|
||||||
|
padding: var(--Spacing-x1) var(--Spacing-x-one-and-half);
|
||||||
|
background: var(--Base-Surface-Secondary-light-Normal);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { env } from "@/env/server"
|
import { env } from "@/env/server"
|
||||||
|
import { getMembershipLevel } from "@/lib/trpc/memoizedRequests"
|
||||||
import { serverClient } from "@/lib/trpc/server"
|
import { serverClient } from "@/lib/trpc/server"
|
||||||
|
|
||||||
import SectionContainer from "@/components/Section/Container"
|
import SectionContainer from "@/components/Section/Container"
|
||||||
@@ -14,7 +15,10 @@ export default async function CurrentRewardsBlock({
|
|||||||
subtitle,
|
subtitle,
|
||||||
link,
|
link,
|
||||||
}: AccountPageComponentProps) {
|
}: AccountPageComponentProps) {
|
||||||
const rewardsResponse = await serverClient().contentstack.rewards.current()
|
const [rewardsResponse, membershipLevel] = await Promise.all([
|
||||||
|
serverClient().contentstack.rewards.current(),
|
||||||
|
getMembershipLevel(),
|
||||||
|
])
|
||||||
|
|
||||||
if (!rewardsResponse?.rewards.length) {
|
if (!rewardsResponse?.rewards.length) {
|
||||||
return null
|
return null
|
||||||
@@ -27,6 +31,7 @@ export default async function CurrentRewardsBlock({
|
|||||||
rewards={rewardsResponse.rewards}
|
rewards={rewardsResponse.rewards}
|
||||||
pageSize={6}
|
pageSize={6}
|
||||||
showRedeem={env.USE_NEW_REWARDS_ENDPOINT && env.USE_NEW_REWARD_MODEL}
|
showRedeem={env.USE_NEW_REWARDS_ENDPOINT && env.USE_NEW_REWARD_MODEL}
|
||||||
|
memberId={membershipLevel?.membershipNumber}
|
||||||
/>
|
/>
|
||||||
<SectionLink link={link} variant="mobile" />
|
<SectionLink link={link} variant="mobile" />
|
||||||
</SectionContainer>
|
</SectionContainer>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"Accept new price": "Accepter ny pris",
|
"Accept new price": "Accepter ny pris",
|
||||||
"Accessibility": "Tilgængelighed",
|
"Accessibility": "Tilgængelighed",
|
||||||
"Accessible Room": "Tilgængelighedsrum",
|
"Accessible Room": "Tilgængelighedsrum",
|
||||||
|
"Active": "Aktiv",
|
||||||
"Activities": "Aktiviteter",
|
"Activities": "Aktiviteter",
|
||||||
"Add Room": "Tilføj værelse",
|
"Add Room": "Tilføj værelse",
|
||||||
"Add code": "Tilføj kode",
|
"Add code": "Tilføj kode",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"Accept new price": "Neuen Preis akzeptieren",
|
"Accept new price": "Neuen Preis akzeptieren",
|
||||||
"Accessibility": "Zugänglichkeit",
|
"Accessibility": "Zugänglichkeit",
|
||||||
"Accessible Room": "Barrierefreies Zimmer",
|
"Accessible Room": "Barrierefreies Zimmer",
|
||||||
|
"Active": "Aktiv",
|
||||||
"Activities": "Aktivitäten",
|
"Activities": "Aktivitäten",
|
||||||
"Add Room": "Zimmer hinzufügen",
|
"Add Room": "Zimmer hinzufügen",
|
||||||
"Add code": "Code hinzufügen",
|
"Add code": "Code hinzufügen",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"Accept new price": "Accept new price",
|
"Accept new price": "Accept new price",
|
||||||
"Accessibility": "Accessibility",
|
"Accessibility": "Accessibility",
|
||||||
"Accessible Room": "Accessibility room",
|
"Accessible Room": "Accessibility room",
|
||||||
|
"Active": "Active",
|
||||||
"Activities": "Activities",
|
"Activities": "Activities",
|
||||||
"Add Room": "Add room",
|
"Add Room": "Add room",
|
||||||
"Add code": "Add code",
|
"Add code": "Add code",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"Accept new price": "Hyväksy uusi hinta",
|
"Accept new price": "Hyväksy uusi hinta",
|
||||||
"Accessibility": "Saavutettavuus",
|
"Accessibility": "Saavutettavuus",
|
||||||
"Accessible Room": "Esteetön huone",
|
"Accessible Room": "Esteetön huone",
|
||||||
|
"Active": "Aktiivinen",
|
||||||
"Activities": "Aktiviteetit",
|
"Activities": "Aktiviteetit",
|
||||||
"Add Room": "Lisää huone",
|
"Add Room": "Lisää huone",
|
||||||
"Add code": "Lisää koodi",
|
"Add code": "Lisää koodi",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"Accept new price": "Aksepterer ny pris",
|
"Accept new price": "Aksepterer ny pris",
|
||||||
"Accessibility": "Tilgjengelighet",
|
"Accessibility": "Tilgjengelighet",
|
||||||
"Accessible Room": "Tilgjengelighetsrom",
|
"Accessible Room": "Tilgjengelighetsrom",
|
||||||
|
"Active": "Aktiv",
|
||||||
"Activities": "Aktiviteter",
|
"Activities": "Aktiviteter",
|
||||||
"Add Room": "Legg til rom",
|
"Add Room": "Legg til rom",
|
||||||
"Add code": "Legg til kode",
|
"Add code": "Legg til kode",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"Accept new price": "Accepter ny pris",
|
"Accept new price": "Accepter ny pris",
|
||||||
"Accessibility": "Tillgänglighet",
|
"Accessibility": "Tillgänglighet",
|
||||||
"Accessible Room": "Tillgänglighetsrum",
|
"Accessible Room": "Tillgänglighetsrum",
|
||||||
|
"Active": "Aktiv",
|
||||||
"Activities": "Aktiviteter",
|
"Activities": "Aktiviteter",
|
||||||
"Add Room": "Lägg till rum",
|
"Add Room": "Lägg till rum",
|
||||||
"Add code": "Lägg till kod",
|
"Add code": "Lägg till kod",
|
||||||
|
|||||||
@@ -161,10 +161,14 @@ export type CMSRewardWithRedeem = z.output<
|
|||||||
|
|
||||||
export type Reward = CMSReward & {
|
export type Reward = CMSReward & {
|
||||||
id: string | undefined
|
id: string | undefined
|
||||||
|
rewardType: string | undefined
|
||||||
|
redeemLocation: string | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RewardWithRedeem = CMSRewardWithRedeem & {
|
export type RewardWithRedeem = CMSRewardWithRedeem & {
|
||||||
id: string | undefined
|
id: string | undefined
|
||||||
|
rewardType: string | undefined
|
||||||
|
redeemLocation: string | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
// New endpoint related types and schemas.
|
// New endpoint related types and schemas.
|
||||||
@@ -172,10 +176,11 @@ export type RewardWithRedeem = CMSRewardWithRedeem & {
|
|||||||
const BenefitReward = z.object({
|
const BenefitReward = z.object({
|
||||||
title: z.string().optional(),
|
title: z.string().optional(),
|
||||||
id: z.string().optional(),
|
id: z.string().optional(),
|
||||||
status: z.string().optional(),
|
redeemLocation: z.string().optional(),
|
||||||
rewardId: z.string().optional(),
|
rewardId: z.string().optional(),
|
||||||
rewardType: z.string().optional(),
|
rewardType: z.string().optional(),
|
||||||
rewardTierLevel: z.string().optional(),
|
rewardTierLevel: z.string().optional(),
|
||||||
|
status: z.string().optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
const CouponState = z.enum(["claimed", "redeemed", "viewed"])
|
const CouponState = z.enum(["claimed", "redeemed", "viewed"])
|
||||||
@@ -191,6 +196,7 @@ const CouponReward = z.object({
|
|||||||
id: z.string().optional(),
|
id: z.string().optional(),
|
||||||
rewardId: z.string().optional(),
|
rewardId: z.string().optional(),
|
||||||
rewardType: z.string().optional(),
|
rewardType: z.string().optional(),
|
||||||
|
redeemLocation: z.string().optional(),
|
||||||
status: z.string().optional(),
|
status: z.string().optional(),
|
||||||
coupon: z.array(CouponData).optional(),
|
coupon: z.array(CouponData).optional(),
|
||||||
})
|
})
|
||||||
@@ -224,3 +230,7 @@ export const validateApiAllTiersSchema = z.record(
|
|||||||
}),
|
}),
|
||||||
z.array(BenefitReward)
|
z.array(BenefitReward)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export type RedeemLocation = "Non-redeemable" | "On-site" | "Online"
|
||||||
|
|
||||||
|
export type RewardType = "Tier" | "Member-voucher" | "Surprise" | "Campaign"
|
||||||
|
|||||||
@@ -245,13 +245,17 @@ export const rewardQueryRouter = router({
|
|||||||
.map(({ rewardId }) => rewardId)
|
.map(({ rewardId }) => rewardId)
|
||||||
|
|
||||||
const rewards = cmsRewards
|
const rewards = cmsRewards
|
||||||
.filter((reward) => !wrappedSurprisesIds.includes(reward.reward_id))
|
.filter((cmsReward) => !wrappedSurprisesIds.includes(cmsReward.reward_id))
|
||||||
.map((reward) => {
|
.map((cmsReward) => {
|
||||||
|
const apiReward = validatedApiRewards.data.find(
|
||||||
|
({ rewardId }) => rewardId === cmsReward.reward_id
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...reward,
|
...cmsReward,
|
||||||
id: validatedApiRewards.data.find(
|
id: apiReward?.id,
|
||||||
({ rewardId }) => rewardId === reward.reward_id
|
rewardType: apiReward?.rewardType,
|
||||||
)?.id,
|
redeemLocation: apiReward?.redeemLocation,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -364,6 +368,8 @@ export const rewardQueryRouter = router({
|
|||||||
return {
|
return {
|
||||||
...reward,
|
...reward,
|
||||||
id: surprise.id,
|
id: surprise.id,
|
||||||
|
rewardType: surprise.rewardType,
|
||||||
|
redeemLocation: surprise.redeemLocation,
|
||||||
coupons: "coupon" in surprise ? surprise.coupon || [] : [],
|
coupons: "coupon" in surprise ? surprise.coupon || [] : [],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,10 +27,12 @@ export interface CurrentRewardsClientProps {
|
|||||||
rewards: (Reward | RewardWithRedeem)[]
|
rewards: (Reward | RewardWithRedeem)[]
|
||||||
pageSize: number
|
pageSize: number
|
||||||
showRedeem: boolean
|
showRedeem: boolean
|
||||||
|
memberId?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RedeemProps {
|
export interface RedeemProps {
|
||||||
reward: RewardWithRedeem
|
reward: RewardWithRedeem
|
||||||
|
memberId?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RedeemModalState = "unmounted" | "hidden" | "visible"
|
export type RedeemModalState = "unmounted" | "hidden" | "visible"
|
||||||
|
|||||||
@@ -1,31 +1,33 @@
|
|||||||
export enum RewardId {
|
export const RewardId = {
|
||||||
// Food & Beverage
|
// Food & Beverage
|
||||||
TenPercentFood = "tier_10_percent_food_tier",
|
TenPercentFood: "tier_10_percent_food_tier",
|
||||||
TwoForOneBreakfast = "tier_2_for_one_breakfast",
|
TwoForOneBreakfast: "tier_2_for_one_breakfast",
|
||||||
FifteenPercentFood = "tier_15_percent_food",
|
FifteenPercentFood: "tier_15_percent_food",
|
||||||
FreeKidsDrink = "tier_free_kids_drink",
|
FreeKidsDrink: "tier_free_kids_drink",
|
||||||
FreeBreakfast = "tier_free_breakfast",
|
FreeBreakfast: "tier_free_breakfast",
|
||||||
|
|
||||||
// Monetary Vouchers
|
// Monetary Vouchers
|
||||||
Bonus50SEK = "tier_50_SEK_bonus_voucher",
|
Bonus50SEK: "tier_50_SEK_bonus_voucher",
|
||||||
Bonus75SEK = "tier_75_SEK_bonus_voucher",
|
Bonus75SEK: "tier_75_SEK_bonus_voucher",
|
||||||
Bonus100SEK = "tier_100_SEK_bonus_voucher",
|
Bonus100SEK: "tier_100_SEK_bonus_voucher",
|
||||||
Bonus150SEK = "tier_150_SEK_bonus_voucher",
|
Bonus150SEK: "tier_150_SEK_bonus_voucher",
|
||||||
Bonus200SEK = "tier_200_SEK_bonus_voucher",
|
Bonus200SEK: "tier_200_SEK_bonus_voucher",
|
||||||
|
|
||||||
// Hotel Perks
|
// Hotel Perks
|
||||||
EarlyCheckin = "tier_early_checkin_tier",
|
EarlyCheckin: "tier_early_checkin_tier",
|
||||||
LateCheckout = "tier_late_checkout",
|
LateCheckout: "tier_late_checkout",
|
||||||
FreeUpgrade = "tier_free_upgrade",
|
FreeUpgrade: "tier_free_upgrade",
|
||||||
RoomGuarantee48H = "tier_48_h_room_guarantee",
|
RoomGuarantee48H: "tier_48_h_room_guarantee",
|
||||||
// GymAccess = "tier_gym_access",
|
// GymAccess: "tier_gym_access",
|
||||||
|
|
||||||
// Earning & Points
|
// Earning & Points
|
||||||
EarnRate25Percent = "tier_25_percent_earn_rate",
|
EarnRate25Percent: "tier_25_percent_earn_rate",
|
||||||
EarnRate50Percent = "tier_50_percent_earn_rate",
|
EarnRate50Percent: "tier_50_percent_earn_rate",
|
||||||
StayBoostForKids = "tier_stay_boost_for_kids",
|
StayBoostForKids: "tier_stay_boost_for_kids",
|
||||||
MemberRate = "tier_member_rate",
|
MemberRate: "tier_member_rate",
|
||||||
|
|
||||||
// Special
|
// Special
|
||||||
YearlyExclusiveGift = "tier_yearly_exclusive_gift",
|
YearlyExclusiveGift: "tier_yearly_exclusive_gift",
|
||||||
}
|
} as const
|
||||||
|
|
||||||
|
export type RewardId = (typeof RewardId)[keyof typeof RewardId]
|
||||||
@@ -1,5 +1,43 @@
|
|||||||
import { RewardId } from "@/types/enums/rewards"
|
import { RewardId } from "@/types/enums/rewards"
|
||||||
|
import type { Reward } from "@/server/routers/contentstack/reward/output"
|
||||||
|
|
||||||
export function isValidRewardId(id: string): id is RewardId {
|
export function isValidRewardId(id: string): id is RewardId {
|
||||||
return Object.values<string>(RewardId).includes(id)
|
return Object.values<string>(RewardId).includes(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const RESTAURANT_REWARD_IDS = [
|
||||||
|
RewardId.TenPercentFood,
|
||||||
|
RewardId.TwoForOneBreakfast,
|
||||||
|
RewardId.FifteenPercentFood,
|
||||||
|
RewardId.FreeKidsDrink,
|
||||||
|
RewardId.FreeBreakfast,
|
||||||
|
] as const
|
||||||
|
|
||||||
|
export type RestaurantRewardId = (typeof RESTAURANT_REWARD_IDS)[number]
|
||||||
|
|
||||||
|
export function isRestaurantReward(
|
||||||
|
rewardId: string
|
||||||
|
): rewardId is RestaurantRewardId {
|
||||||
|
return RESTAURANT_REWARD_IDS.some((id) => id === rewardId)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function redeemLocationIsOnSite(
|
||||||
|
location: Reward["redeemLocation"]
|
||||||
|
): location is "On-site" {
|
||||||
|
return location === "On-site"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTierType(type: Reward["rewardType"]): type is "Tier" {
|
||||||
|
return type === "Tier"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isOnSiteTierReward(reward: Reward): boolean {
|
||||||
|
return (
|
||||||
|
redeemLocationIsOnSite(reward.redeemLocation) &&
|
||||||
|
isTierType(reward.rewardType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRestaurantOnSiteTierReward(reward: Reward): boolean {
|
||||||
|
return isOnSiteTierReward(reward) && isRestaurantReward(reward.reward_id)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user