Files
web/apps/scandic-web/components/Modal/index.tsx
Pontus Dreij 2509794d0c Merged in feat/SW-1676-modify-contact-details-my-stay-anonymous (pull request #1468)
Feat/SW-1676 modify contact details my stay anonymous

* feat(SW-1676): Modify guest details step 1

* feat(SW-1676) Integration to api to update guest details

* feat(SW-1676) Reuse of old modal

* feat(SW-1676) updated modify guest

* feat(SW-1676) cleanup

* feat(SW-1676) updated myStayReturnRoute to sessionStorage


Approved-by: Niclas Edenvin
2025-03-07 13:41:25 +00:00

191 lines
4.6 KiB
TypeScript

"use client"
import { motion } from "framer-motion"
import { type PropsWithChildren, useEffect, useState } from "react"
import {
Dialog,
DialogTrigger,
Modal as AriaModal,
ModalOverlay,
} from "react-aria-components"
import { useIntl } from "react-intl"
import { CloseLargeIcon } from "@/components/Icons"
import Preamble from "@/components/TempDesignSystem/Text/Preamble"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import {
type AnimationState,
AnimationStateEnum,
type InnerModalProps,
type ModalProps,
} from "./modal"
import { fade, slideInOut } from "./motionVariants"
import { modalContentVariants } from "./variants"
import styles from "./modal.module.css"
const MotionOverlay = motion(ModalOverlay)
const MotionModal = motion(AriaModal)
function InnerModal({
animation,
onAnimationComplete = () => undefined,
setAnimation,
onToggle,
isOpen,
children,
title,
subtitle,
withActions,
hideHeader,
}: PropsWithChildren<InnerModalProps>) {
const intl = useIntl()
const contentClassNames = modalContentVariants({
withActions: withActions,
})
function modalStateHandler(newAnimationState: AnimationState) {
setAnimation((currentAnimationState) =>
newAnimationState === AnimationStateEnum.hidden &&
currentAnimationState === AnimationStateEnum.hidden
? AnimationStateEnum.unmounted
: currentAnimationState
)
if (newAnimationState === AnimationStateEnum.visible) {
onAnimationComplete()
}
}
function onOpenChange(state: boolean) {
onToggle!(state)
}
return (
<MotionOverlay
animate={animation}
className={styles.overlay}
initial={"hidden"}
isDismissable
isExiting={animation === AnimationStateEnum.hidden}
onAnimationComplete={modalStateHandler}
variants={fade}
isOpen={isOpen}
onOpenChange={onOpenChange}
>
<MotionModal
className={styles.modal}
variants={slideInOut}
animate={animation}
initial={"hidden"}
>
<Dialog
className={styles.dialog}
aria-label={intl.formatMessage({ id: "Dialog" })}
>
{({ close }) => (
<>
{!hideHeader && (
<header
className={`${styles.header} ${!subtitle ? styles.verticalCenter : ""}`}
>
<div>
{title && (
<Subtitle type="one" color="uiTextHighContrast">
{title}
</Subtitle>
)}
{subtitle && (
<Preamble asChild>
<span>{subtitle}</span>
</Preamble>
)}
</div>
<button
onClick={close}
type="button"
className={styles.close}
>
<CloseLargeIcon color="uiTextMediumContrast" />
</button>
</header>
)}
<section className={contentClassNames}>{children}</section>
</>
)}
</Dialog>
</MotionModal>
</MotionOverlay>
)
}
export default function Modal({
onAnimationComplete = () => undefined,
trigger,
isOpen,
onToggle,
title,
subtitle,
children,
withActions = false,
hideHeader = false,
}: PropsWithChildren<ModalProps>) {
const [animation, setAnimation] = useState<AnimationState>(
AnimationStateEnum.visible
)
useEffect(() => {
if (typeof isOpen === "boolean") {
setAnimation(
isOpen ? AnimationStateEnum.visible : AnimationStateEnum.hidden
)
}
if (isOpen === undefined) {
setAnimation(AnimationStateEnum.unmounted)
}
}, [isOpen])
if (!trigger) {
return (
<InnerModal
onAnimationComplete={onAnimationComplete}
animation={animation}
setAnimation={setAnimation}
onToggle={onToggle}
isOpen={isOpen}
title={title}
subtitle={subtitle}
withActions={withActions}
hideHeader={hideHeader}
>
{children}
</InnerModal>
)
}
return (
<DialogTrigger
onOpenChange={(isOpen) =>
setAnimation(
isOpen ? AnimationStateEnum.visible : AnimationStateEnum.hidden
)
}
>
{trigger}
<InnerModal
onAnimationComplete={onAnimationComplete}
animation={animation}
setAnimation={setAnimation}
title={title}
subtitle={subtitle}
withActions={withActions}
>
{children}
</InnerModal>
</DialogTrigger>
)
}