Merged in chore/LOY-175-remove-references-to-old-rewards (pull request #1519)
Chore/LOY-175 remove references to old rewards and refactor reward typing Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
+4
-15
@@ -19,10 +19,7 @@ import Redeem from "../Redeem"
|
||||
import styles from "./current.module.css"
|
||||
|
||||
import type { CurrentRewardsClientProps } from "@/types/components/myPages/myPage/accountPage"
|
||||
import type {
|
||||
Reward,
|
||||
RewardWithRedeem,
|
||||
} from "@/server/routers/contentstack/reward/output"
|
||||
import type { Reward } from "@/types/components/myPages/rewards"
|
||||
|
||||
export default function ClientCurrentRewards({
|
||||
rewards: initialData,
|
||||
@@ -34,7 +31,7 @@ export default function ClientCurrentRewards({
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
|
||||
const { data } = trpc.contentstack.rewards.current.useQuery<{
|
||||
rewards: (Reward | RewardWithRedeem)[]
|
||||
rewards: Reward[]
|
||||
}>(
|
||||
{
|
||||
lang,
|
||||
@@ -70,21 +67,13 @@ export default function ClientCurrentRewards({
|
||||
<div ref={containerRef} className={styles.container}>
|
||||
<Grids.Stackable>
|
||||
{paginatedRewards.map((reward, idx) => {
|
||||
const earliestExpirationDate =
|
||||
"coupons" in reward
|
||||
? getEarliestExpirationDate(reward.coupons)
|
||||
: null
|
||||
const earliestExpirationDate = getEarliestExpirationDate(reward)
|
||||
|
||||
return (
|
||||
<article className={styles.card} key={`${reward.reward_id}-${idx}`}>
|
||||
<div className={styles.content}>
|
||||
<RewardIcon rewardId={reward.reward_id} />
|
||||
{showRedeem && (
|
||||
<ScriptedRewardText
|
||||
rewardType={reward.rewardType}
|
||||
rewardTierLevel={reward.rewardTierLevel}
|
||||
/>
|
||||
)}
|
||||
{showRedeem && <ScriptedRewardText reward={reward} />}
|
||||
<Title
|
||||
as="h4"
|
||||
level="h3"
|
||||
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
.overlay {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
height: var(--visual-viewport-height);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.modal {
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
box-shadow: 0px 4px 24px 0px rgba(38, 32, 30, 0.08);
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 101;
|
||||
max-height: 90vh;
|
||||
display: flex;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
}
|
||||
|
||||
.dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modalHeader {
|
||||
--button-height: 32px;
|
||||
box-sizing: content-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: var(--button-height);
|
||||
position: relative;
|
||||
justify-content: center;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
||||
border-bottom: 1px solid var(--Border-Divider-Subtle);
|
||||
}
|
||||
|
||||
.modalContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x4);
|
||||
padding: var(--Spacing-x3);
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.modalFooter {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
gap: var(--Spacing-x2);
|
||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
||||
background-color: var(--Base-Surface-Secondary-light-Normal);
|
||||
border-bottom-left-radius: var(--Corner-radius-Medium);
|
||||
border-bottom-right-radius: var(--Corner-radius-Medium);
|
||||
}
|
||||
|
||||
.modalClose {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: var(--Spacing-x3);
|
||||
width: 32px;
|
||||
height: var(--button-height);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.filterSection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x2);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.checkboxGroup {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.checkboxGroup > * {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.filterButton {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x1);
|
||||
place-self: flex-start;
|
||||
}
|
||||
|
||||
.filterCount {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--Base-Text-Inverted);
|
||||
background-color: var(--Base-Text-Accent);
|
||||
border-radius: var(--Corner-radius-Rounded);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: var(--typography-Footnote-Regular-fontSize);
|
||||
}
|
||||
|
||||
.customFormCheckbox {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.customCheckbox {
|
||||
display: flex;
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.customCheckbox[data-selected] .checkbox {
|
||||
border: none;
|
||||
background: var(--UI-Input-Controls-Fill-Selected);
|
||||
}
|
||||
|
||||
.customCheckbox[data-disabled] .checkbox {
|
||||
border: 1px solid var(--UI-Input-Controls-Border-Disabled);
|
||||
background: var(--UI-Input-Controls-Surface-Disabled);
|
||||
}
|
||||
|
||||
.customCheckbox[data-focus-visible="true"] {
|
||||
outline: 2px solid var(--UI-Input-Controls-Fill-Selected);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.checkboxContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x-one-and-half);
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
min-width: 24px;
|
||||
background: var(--UI-Input-Controls-Surface-Normal);
|
||||
border: 1px solid var(--UI-Input-Controls-Border-Normal);
|
||||
border-radius: 4px;
|
||||
transition: all 200ms;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.overlay {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal {
|
||||
left: auto;
|
||||
bottom: auto;
|
||||
width: min(933px, 80vw);
|
||||
max-height: 80vh;
|
||||
}
|
||||
|
||||
.checkboxGroup {
|
||||
gap: var(--Spacing-x5);
|
||||
}
|
||||
}
|
||||
-247
@@ -1,247 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { motion } from "framer-motion"
|
||||
import { useState } from "react"
|
||||
import {
|
||||
Checkbox,
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
Modal,
|
||||
ModalOverlay,
|
||||
} from "react-aria-components"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import {
|
||||
type MembershipLevelEnum,
|
||||
TIER_TO_FRIEND_MAP,
|
||||
} from "@/constants/membershipLevels"
|
||||
|
||||
import { CloseLargeIcon, FilterIcon } from "@/components/Icons"
|
||||
import CheckIcon from "@/components/Icons/Check"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
|
||||
import styles from "./filterRewardsModal.module.css"
|
||||
|
||||
import type {
|
||||
FilterRewardsModalProps,
|
||||
RewardCategory,
|
||||
} from "@/types/components/myPages/rewards"
|
||||
|
||||
type ModalState = "visible" | "hidden" | "unmounted"
|
||||
|
||||
export default function FilterRewardsModal({
|
||||
selectedCategories,
|
||||
selectedLevels,
|
||||
onCategoriesChange,
|
||||
onLevelsChange,
|
||||
availableTierLevels,
|
||||
availableCategories,
|
||||
}: FilterRewardsModalProps) {
|
||||
const intl = useIntl()
|
||||
|
||||
const [animation, setAnimation] = useState<ModalState>("unmounted")
|
||||
const [tempCategories, setTempCategories] =
|
||||
useState<RewardCategory[]>(selectedCategories)
|
||||
const [tempLevels, setTempLevels] =
|
||||
useState<MembershipLevelEnum[]>(selectedLevels)
|
||||
|
||||
const categoryTranslations: Record<RewardCategory, string> = {
|
||||
Restaurants: intl.formatMessage({ id: "Restaurants" }),
|
||||
Bar: intl.formatMessage({ id: "Bar" }),
|
||||
Voucher: intl.formatMessage({ id: "Voucher" }),
|
||||
"Services and rooms": intl.formatMessage({ id: "Services and rooms" }),
|
||||
"Spa and gym": intl.formatMessage({ id: "Spa and gym" }),
|
||||
}
|
||||
|
||||
function handleClearAll() {
|
||||
setTempCategories([])
|
||||
setTempLevels([])
|
||||
}
|
||||
|
||||
function handleApply(close: () => void) {
|
||||
onCategoriesChange(tempCategories)
|
||||
onLevelsChange(tempLevels)
|
||||
close()
|
||||
}
|
||||
|
||||
function handleOpenChange(isOpen: boolean) {
|
||||
setAnimation(isOpen ? "visible" : "hidden")
|
||||
if (isOpen) {
|
||||
setTempCategories(selectedCategories)
|
||||
setTempLevels(selectedLevels)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<DialogTrigger onOpenChange={handleOpenChange}>
|
||||
<Button intent="text" theme="base" className={styles.filterButton}>
|
||||
<FilterIcon color="burgundy" />
|
||||
{intl.formatMessage({ id: "Filter and sort" })}
|
||||
{(selectedCategories.length > 0 || selectedLevels.length > 0) && (
|
||||
<span className={styles.filterCount}>
|
||||
{selectedCategories.length + selectedLevels.length}
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<MotionOverlay
|
||||
className={styles.overlay}
|
||||
isExiting={animation === "hidden"}
|
||||
onAnimationComplete={(state) => {
|
||||
if (state === "hidden") {
|
||||
setAnimation("unmounted")
|
||||
}
|
||||
}}
|
||||
variants={variants.fade}
|
||||
initial="hidden"
|
||||
animate={animation}
|
||||
>
|
||||
<MotionModal
|
||||
className={styles.modal}
|
||||
variants={variants.slideInOut}
|
||||
initial="hidden"
|
||||
animate={animation}
|
||||
>
|
||||
<Dialog className={styles.dialog}>
|
||||
{({ close }) => (
|
||||
<>
|
||||
<header className={styles.modalHeader}>
|
||||
<Body textTransform="bold" color="black">
|
||||
{intl.formatMessage({ id: "Filter and sort" })}
|
||||
</Body>
|
||||
<button
|
||||
onClick={close}
|
||||
type="button"
|
||||
className={styles.modalClose}
|
||||
>
|
||||
<CloseLargeIcon />
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div className={styles.modalContent}>
|
||||
{availableCategories.length > 0 && (
|
||||
<div className={styles.filterSection}>
|
||||
<Subtitle type="two" color="black">
|
||||
{intl.formatMessage({ id: "Category" })}
|
||||
</Subtitle>
|
||||
<div className={styles.checkboxGroup} role="group">
|
||||
{availableCategories.map((category) => (
|
||||
<Checkbox
|
||||
key={category}
|
||||
value={category}
|
||||
isSelected={tempCategories.includes(category)}
|
||||
onChange={(isSelected) => {
|
||||
setTempCategories(
|
||||
isSelected
|
||||
? [...tempCategories, category]
|
||||
: tempCategories.filter((c) => c !== category)
|
||||
)
|
||||
}}
|
||||
className={styles.customCheckbox}
|
||||
>
|
||||
{({ isSelected }) => (
|
||||
<span className={styles.checkboxContainer}>
|
||||
<span className={styles.checkbox}>
|
||||
{isSelected && <CheckIcon color="white" />}
|
||||
</span>
|
||||
{categoryTranslations[category]}
|
||||
</span>
|
||||
)}
|
||||
</Checkbox>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{availableTierLevels.length > 0 && (
|
||||
<div className={styles.filterSection}>
|
||||
<Subtitle type="two" color="black">
|
||||
{intl.formatMessage({ id: "Level benefit" })}
|
||||
</Subtitle>
|
||||
<div className={styles.checkboxGroup} role="group">
|
||||
{availableTierLevels.map((level) => (
|
||||
<Checkbox
|
||||
key={level}
|
||||
value={level}
|
||||
isSelected={tempLevels.includes(level)}
|
||||
onChange={(isSelected) => {
|
||||
setTempLevels(
|
||||
isSelected
|
||||
? [...tempLevels, level]
|
||||
: tempLevels.filter((l) => l !== level)
|
||||
)
|
||||
}}
|
||||
className={styles.customCheckbox}
|
||||
>
|
||||
{({ isSelected }) => (
|
||||
<span className={styles.checkboxContainer}>
|
||||
<span className={styles.checkbox}>
|
||||
{isSelected && <CheckIcon color="white" />}
|
||||
</span>
|
||||
{TIER_TO_FRIEND_MAP[level]}
|
||||
</span>
|
||||
)}
|
||||
</Checkbox>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<footer className={styles.modalFooter}>
|
||||
<Button
|
||||
onClick={handleClearAll}
|
||||
intent="text"
|
||||
theme="base"
|
||||
className={styles.clearButton}
|
||||
>
|
||||
{intl.formatMessage({ id: "Clear all filters" })}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => handleApply(close)}
|
||||
intent="secondary"
|
||||
theme="base"
|
||||
className={styles.applyButton}
|
||||
>
|
||||
{intl.formatMessage({ id: "Apply" })}
|
||||
</Button>
|
||||
</footer>
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
</MotionModal>
|
||||
</MotionOverlay>
|
||||
</DialogTrigger>
|
||||
)
|
||||
}
|
||||
|
||||
const MotionOverlay = motion(ModalOverlay)
|
||||
const MotionModal = motion(Modal)
|
||||
|
||||
const variants = {
|
||||
fade: {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
transition: { duration: 0.4, ease: "easeInOut" },
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.4, ease: "easeInOut" },
|
||||
},
|
||||
},
|
||||
|
||||
slideInOut: {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
y: 32,
|
||||
transition: { duration: 0.4, ease: "easeInOut" },
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.4, ease: "easeInOut" },
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export default async function CurrentRewardsBlock({
|
||||
<SectionHeader title={title} link={link} preamble={subtitle} />
|
||||
<ClientCurrentRewards
|
||||
rewards={rewardsResponse.rewards}
|
||||
showRedeem={env.USE_NEW_REWARDS_ENDPOINT && env.USE_NEW_REWARD_MODEL}
|
||||
showRedeem={env.USE_NEW_REWARD_MODEL}
|
||||
membershipNumber={membershipLevel?.membershipNumber}
|
||||
/>
|
||||
<SectionLink link={link} variant="mobile" />
|
||||
|
||||
@@ -10,17 +10,13 @@ import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { toast } from "@/components/TempDesignSystem/Toasts"
|
||||
|
||||
import { RewardIcon } from "../../RewardIcon"
|
||||
import useRedeemFlow from "../useRedeemFlow"
|
||||
|
||||
import styles from "../redeem.module.css"
|
||||
|
||||
export default function Campaign() {
|
||||
const { reward } = useRedeemFlow()
|
||||
const intl = useIntl()
|
||||
import type { Campaign } from "@/types/components/myPages/rewards"
|
||||
|
||||
if (!reward) {
|
||||
return null
|
||||
}
|
||||
export default function Campaign({ reward }: { reward: Campaign }) {
|
||||
const intl = useIntl()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -16,20 +16,19 @@ import useRedeemFlow from "../useRedeemFlow"
|
||||
|
||||
import styles from "../redeem.module.css"
|
||||
|
||||
import type { Surprise, Tier } from "@/types/components/myPages/rewards"
|
||||
|
||||
export default function Tier({
|
||||
reward,
|
||||
membershipNumber,
|
||||
}: {
|
||||
reward: Tier | Surprise
|
||||
membershipNumber: string
|
||||
}) {
|
||||
const { reward, onRedeem, redeemStep, setRedeemStep, isRedeeming } =
|
||||
useRedeemFlow()
|
||||
const { onRedeem, redeemStep, setRedeemStep, isRedeeming } = useRedeemFlow()
|
||||
|
||||
const intl = useIntl()
|
||||
|
||||
if (!reward) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.modalContent}>
|
||||
@@ -93,7 +92,7 @@ export default function Tier({
|
||||
{redeemStep === "confirmation" && (
|
||||
<footer className={styles.modalFooter}>
|
||||
<Button
|
||||
onClick={onRedeem}
|
||||
onClick={() => onRedeem(reward)}
|
||||
disabled={isRedeeming}
|
||||
intent="primary"
|
||||
theme="base"
|
||||
|
||||
@@ -17,8 +17,8 @@ import Button from "@/components/TempDesignSystem/Button"
|
||||
import useLang from "@/hooks/useLang"
|
||||
import { isRestaurantOnSiteTierReward } from "@/utils/rewards"
|
||||
|
||||
import Campaign from "./Flows/Campaign"
|
||||
import Tier from "./Flows/Tier"
|
||||
import RedeemCampaign from "./Flows/Campaign"
|
||||
import RedeemTier from "./Flows/Tier"
|
||||
import { ConfirmClose } from "./ConfirmClose"
|
||||
import { RedeemContext } from "./useRedeemFlow"
|
||||
|
||||
@@ -29,7 +29,7 @@ import type {
|
||||
RedeemProps,
|
||||
RedeemStep,
|
||||
} from "@/types/components/myPages/myPage/accountPage"
|
||||
import type { RewardWithRedeem } from "@/server/routers/contentstack/reward/output"
|
||||
import type { Reward } from "@/types/components/myPages/rewards"
|
||||
|
||||
const MotionOverlay = motion(ModalOverlay)
|
||||
const MotionModal = motion(Modal)
|
||||
@@ -58,7 +58,6 @@ export default function Redeem({ reward, membershipNumber }: RedeemProps) {
|
||||
return (
|
||||
<RedeemContext.Provider
|
||||
value={{
|
||||
reward,
|
||||
redeemStep,
|
||||
setRedeemStep,
|
||||
defaultTimeRemaining: thirtyMinutesInMs,
|
||||
@@ -164,15 +163,16 @@ const variants = {
|
||||
},
|
||||
}
|
||||
|
||||
function getRedeemFlow(reward: RewardWithRedeem, membershipNumber: string) {
|
||||
switch (reward.rewardType) {
|
||||
function getRedeemFlow(reward: Reward, membershipNumber: string) {
|
||||
const { rewardType } = reward
|
||||
switch (rewardType) {
|
||||
case "Campaign":
|
||||
return <Campaign />
|
||||
return <RedeemCampaign reward={reward} />
|
||||
case "Surprise":
|
||||
case "Tier":
|
||||
return <Tier membershipNumber={membershipNumber} />
|
||||
return <RedeemTier reward={reward} membershipNumber={membershipNumber} />
|
||||
default:
|
||||
console.warn("Unsupported reward type for redeem:", reward.rewardType)
|
||||
console.warn("Unsupported reward type for redeem:", rewardType)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ import { createContext, useCallback, useContext, useEffect } from "react"
|
||||
|
||||
import { trpc } from "@/lib/trpc/client"
|
||||
|
||||
import { getFirstRedeemableCoupon } from "@/utils/rewards"
|
||||
|
||||
import type { RedeemFlowContext } from "@/types/components/myPages/myPage/accountPage"
|
||||
import type { RewardWithRedeem } from "@/server/routers/contentstack/reward/output"
|
||||
import type { Reward } from "@/types/components/myPages/rewards"
|
||||
|
||||
export const RedeemContext = createContext<RedeemFlowContext>({
|
||||
reward: null,
|
||||
redeemStep: "initial",
|
||||
setRedeemStep: () => undefined,
|
||||
defaultTimeRemaining: 0,
|
||||
@@ -18,7 +19,6 @@ export const RedeemContext = createContext<RedeemFlowContext>({
|
||||
|
||||
export default function useRedeemFlow() {
|
||||
const {
|
||||
reward,
|
||||
redeemStep,
|
||||
setRedeemStep,
|
||||
defaultTimeRemaining,
|
||||
@@ -27,13 +27,14 @@ export default function useRedeemFlow() {
|
||||
} = useContext(RedeemContext)
|
||||
|
||||
const update = trpc.contentstack.rewards.redeem.useMutation<{
|
||||
rewards: RewardWithRedeem[]
|
||||
rewards: Reward[]
|
||||
}>()
|
||||
|
||||
const onRedeem = useCallback(() => {
|
||||
if (reward?.id) {
|
||||
const onRedeem = useCallback(
|
||||
(reward: Reward) => {
|
||||
const coupon = getFirstRedeemableCoupon(reward)
|
||||
update.mutate(
|
||||
{ rewardId: reward.id, couponCode: reward.couponCode },
|
||||
{ rewardId: reward.id, couponCode: coupon.couponCode },
|
||||
{
|
||||
onSuccess() {
|
||||
setRedeemStep("redeemed")
|
||||
@@ -43,8 +44,9 @@ export default function useRedeemFlow() {
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
}, [reward, update, setRedeemStep])
|
||||
},
|
||||
[update, setRedeemStep]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (redeemStep === "initial") {
|
||||
@@ -53,7 +55,6 @@ export default function useRedeemFlow() {
|
||||
}, [redeemStep, setTimeRemaining, defaultTimeRemaining])
|
||||
|
||||
return {
|
||||
reward,
|
||||
onRedeem,
|
||||
redeemStep,
|
||||
setRedeemStep,
|
||||
|
||||
+7
-9
@@ -4,24 +4,22 @@ import { TIER_TO_FRIEND_MAP } from "@/constants/membershipLevels"
|
||||
|
||||
import BiroScript from "@/components/TempDesignSystem/Text/BiroScript"
|
||||
import { isMembershipLevel } from "@/utils/membershipLevels"
|
||||
import { getRewardType } from "@/utils/rewards"
|
||||
|
||||
import type { ScriptedRewardTextProps } from "@/types/components/myPages/myPage/accountPage"
|
||||
|
||||
export default function ScriptedRewardText({
|
||||
rewardType,
|
||||
rewardTierLevel,
|
||||
reward,
|
||||
}: ScriptedRewardTextProps) {
|
||||
const intl = useIntl()
|
||||
|
||||
function getLabel(rewardType?: string, rewardTierLevel?: string) {
|
||||
const type = getRewardType(rewardType)
|
||||
|
||||
switch (type) {
|
||||
case "Tier":
|
||||
function getLabel() {
|
||||
switch (reward.rewardType) {
|
||||
case "Tier": {
|
||||
const { rewardTierLevel } = reward
|
||||
return rewardTierLevel && isMembershipLevel(rewardTierLevel)
|
||||
? TIER_TO_FRIEND_MAP[rewardTierLevel]
|
||||
: null
|
||||
}
|
||||
case "Campaign":
|
||||
return intl.formatMessage({ id: "Campaign" })
|
||||
case "Surprise":
|
||||
@@ -33,7 +31,7 @@ export default function ScriptedRewardText({
|
||||
}
|
||||
}
|
||||
|
||||
const label = getLabel(rewardType, rewardTierLevel)
|
||||
const label = getLabel()
|
||||
|
||||
if (!label) return null
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import Slide from "./Slide"
|
||||
import styles from "./surprises.module.css"
|
||||
|
||||
import type { SurprisesProps } from "@/types/components/blocks/surprises"
|
||||
import type { Surprise } from "@/server/routers/contentstack/reward/output"
|
||||
import type { Surprise } from "@/types/components/myPages/rewards"
|
||||
|
||||
const MotionModal = motion(Modal)
|
||||
|
||||
@@ -125,7 +125,7 @@ export default function SurprisesNotification({
|
||||
async function viewRewards() {
|
||||
const updates = surprises
|
||||
.map((surprise) => {
|
||||
const coupons = surprise.coupons
|
||||
const coupons = surprise.coupon
|
||||
.map((coupon) => {
|
||||
if (coupon.couponCode) {
|
||||
return {
|
||||
|
||||
@@ -7,7 +7,7 @@ import Card from "./Card"
|
||||
import type { SlideProps } from "@/types/components/blocks/surprises"
|
||||
|
||||
export default function Slide({ surprise }: SlideProps) {
|
||||
const earliestExpirationDate = getEarliestExpirationDate(surprise.coupons)
|
||||
const earliestExpirationDate = getEarliestExpirationDate(surprise)
|
||||
|
||||
return (
|
||||
<Card title={surprise.label}>
|
||||
|
||||
Reference in New Issue
Block a user