Files
web/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/index.tsx
Matilda Landström 5de2a993a7 Merged in feat/SW-1711-switch-icons (pull request #1558)
Switches out all the old icons to new ones, and moves them to the design system. The new icons are of three different types: Materialise Symbol, Nucleo, and Customized. Also adds further mapping between facilities/amenities and icons.

Approved-by: Michael Zetterberg
Approved-by: Erik Tiekstra
2025-03-27 09:42:52 +00:00

180 lines
5.1 KiB
TypeScript

"use client"
import { motion } from "framer-motion"
import { useState } from "react"
import {
Dialog,
DialogTrigger,
Modal,
ModalOverlay,
} from "react-aria-components"
import { useIntl } from "react-intl"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons"
import { trpc } from "@/lib/trpc/client"
import Button from "@/components/TempDesignSystem/Button"
import useLang from "@/hooks/useLang"
import { isRestaurantOnSiteTierReward } from "@/utils/rewards"
import RedeemCampaign from "./Flows/Campaign"
import RedeemTier from "./Flows/Tier"
import { ConfirmClose } from "./ConfirmClose"
import { RedeemContext } from "./useRedeemFlow"
import styles from "./redeem.module.css"
import type {
RedeemModalState,
RedeemProps,
RedeemStep,
} from "@/types/components/myPages/myPage/accountPage"
import type { Reward } from "@/types/components/myPages/rewards"
const MotionOverlay = motion(ModalOverlay)
const MotionModal = motion(Modal)
const thirtyMinutesInMs = 1000 * 60 * 30
export default function Redeem({ reward, membershipNumber }: RedeemProps) {
const [animation, setAnimation] = useState<RedeemModalState>("unmounted")
const intl = useIntl()
const lang = useLang()
const utils = trpc.useUtils()
const [redeemStep, setRedeemStep] = useState<RedeemStep>("initial")
const [timeRemaining, setTimeRemaining] = useState(thirtyMinutesInMs)
function modalStateHandler(newAnimationState: RedeemModalState) {
setAnimation((currentAnimationState) =>
newAnimationState === "hidden" && currentAnimationState === "hidden"
? "unmounted"
: currentAnimationState
)
if (newAnimationState === "unmounted") {
setRedeemStep("initial")
}
}
return (
<RedeemContext.Provider
value={{
redeemStep,
setRedeemStep,
defaultTimeRemaining: thirtyMinutesInMs,
timeRemaining,
setTimeRemaining,
}}
>
<DialogTrigger
onOpenChange={(isOpen) => setAnimation(isOpen ? "visible" : "hidden")}
>
<Button intent="primary" fullWidth>
{reward.redeemLocation === "Non-redeemable"
? intl.formatMessage({ id: "How to use" })
: intl.formatMessage({ id: "Open" })}
</Button>
<MotionOverlay
className={styles.overlay}
isExiting={animation === "hidden"}
onAnimationComplete={modalStateHandler}
variants={variants.fade}
initial="hidden"
animate={animation}
>
<MotionModal
className={styles.modal}
variants={variants.slideInOut}
initial="hidden"
animate={animation}
>
<Dialog className={styles.dialog} aria-label={reward.label}>
{({ close }) => {
function closeModal() {
if (
redeemStep === "redeemed" ||
redeemStep === "confirm-close"
) {
utils.contentstack.rewards.current.invalidate({
lang,
})
}
close()
}
return (
<>
<header className={styles.modalHeader}>
<button
onClick={() => {
if (
redeemStep === "redeemed" &&
!isRestaurantOnSiteTierReward(reward)
) {
setRedeemStep("confirm-close")
} else {
closeModal()
}
}}
type="button"
className={styles.modalClose}
>
<MaterialIcon icon="close" />
</button>
</header>
{redeemStep === "confirm-close" ? (
<ConfirmClose close={closeModal} />
) : (
getRedeemFlow(reward, membershipNumber || "")
)}
</>
)
}}
</Dialog>
</MotionModal>
</MotionOverlay>
</DialogTrigger>
</RedeemContext.Provider>
)
}
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" },
},
},
}
function getRedeemFlow(reward: Reward, membershipNumber: string) {
const { rewardType } = reward
switch (rewardType) {
case "Campaign":
return <RedeemCampaign reward={reward} />
case "Surprise":
case "Tier":
return <RedeemTier reward={reward} membershipNumber={membershipNumber} />
default:
console.warn("Unsupported reward type for redeem:", rewardType)
return null
}
}