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
This commit is contained in:
Pontus Dreij
2025-03-07 13:41:25 +00:00
parent 2c7d72c540
commit 2509794d0c
33 changed files with 528 additions and 251 deletions
@@ -0,0 +1,69 @@
import { CloseLargeIcon } from "@/components/Icons"
import Button from "@/components/TempDesignSystem/Button"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import styles from "./modalContent.module.css"
import type { ReactNode } from "react"
interface ModalContentProps {
title?: string
content: ReactNode
primaryAction: {
label: string
onClick: () => void
intent?: "primary" | "secondary" | "text"
isLoading?: boolean
disabled?: boolean
} | null
secondaryAction: {
label: string
onClick: () => void
intent?: "primary" | "secondary" | "text"
} | null
onClose?: () => void
}
export function ModalContentWithActions({
title,
content,
primaryAction,
secondaryAction,
onClose,
}: ModalContentProps) {
return (
<>
{title && (
<header className={styles.header}>
<Subtitle>{title}</Subtitle>
<button onClick={onClose} type="button" className={styles.close}>
<CloseLargeIcon color="uiTextMediumContrast" />
</button>
</header>
)}
<div className={styles.content}>{content}</div>
<footer className={styles.footer}>
{secondaryAction && (
<Button
theme="base"
intent={secondaryAction.intent ?? "text"}
color="burgundy"
onClick={secondaryAction.onClick}
>
{secondaryAction.label}
</Button>
)}
{primaryAction && (
<Button
theme="base"
intent={primaryAction.intent ?? "secondary"}
onClick={primaryAction.onClick}
disabled={primaryAction.isLoading || primaryAction.disabled}
>
{primaryAction.label}
</Button>
)}
</footer>
</>
)
}
@@ -0,0 +1,45 @@
.content {
display: flex;
flex-direction: column;
gap: var(--Spacing-x3);
padding: var(--Spacing-x1) var(--Spacing-x3) var(--Spacing-x4);
max-height: 70vh;
overflow-y: auto;
width: 100%;
}
.header {
display: flex;
justify-content: space-between;
width: 100%;
padding: var(--Spacing-x3) var(--Spacing-x3) var(--Spacing-x1)
var(--Spacing-x3);
}
.footer {
display: flex;
justify-content: space-between;
width: 100%;
border-top: 1px solid var(--Base-Border-Subtle);
padding: var(--Spacing-x3);
}
.close {
background: none;
border: none;
cursor: pointer;
position: absolute;
display: flex;
align-items: center;
padding: 0;
justify-content: center;
top: 20px;
right: 20px;
}
@media screen and (min-width: 768px) {
.content {
width: 640px;
max-width: 100%;
}
}
+39 -20
View File
@@ -21,6 +21,7 @@ import {
type ModalProps,
} from "./modal"
import { fade, slideInOut } from "./motionVariants"
import { modalContentVariants } from "./variants"
import styles from "./modal.module.css"
@@ -36,9 +37,15 @@ function InnerModal({
children,
title,
subtitle,
withActions,
hideHeader,
}: PropsWithChildren<InnerModalProps>) {
const intl = useIntl()
const contentClassNames = modalContentVariants({
withActions: withActions,
})
function modalStateHandler(newAnimationState: AnimationState) {
setAnimation((currentAnimationState) =>
newAnimationState === AnimationStateEnum.hidden &&
@@ -79,27 +86,34 @@ function InnerModal({
>
{({ close }) => (
<>
<header
className={`${styles.header} ${!subtitle ? styles.verticalCenter : ""}`}
>
<div>
{title && (
<Subtitle type="one" color="uiTextHighContrast">
{title}
</Subtitle>
)}
{subtitle && (
<Preamble asChild>
<span>{subtitle}</span>
</Preamble>
)}
</div>
{!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={styles.content}>{children}</section>
<button
onClick={close}
type="button"
className={styles.close}
>
<CloseLargeIcon color="uiTextMediumContrast" />
</button>
</header>
)}
<section className={contentClassNames}>{children}</section>
</>
)}
</Dialog>
@@ -116,6 +130,8 @@ export default function Modal({
title,
subtitle,
children,
withActions = false,
hideHeader = false,
}: PropsWithChildren<ModalProps>) {
const [animation, setAnimation] = useState<AnimationState>(
AnimationStateEnum.visible
@@ -142,6 +158,8 @@ export default function Modal({
isOpen={isOpen}
title={title}
subtitle={subtitle}
withActions={withActions}
hideHeader={hideHeader}
>
{children}
</InnerModal>
@@ -163,6 +181,7 @@ export default function Modal({
setAnimation={setAnimation}
title={title}
subtitle={subtitle}
withActions={withActions}
>
{children}
</InnerModal>
@@ -49,10 +49,17 @@
flex-direction: column;
align-items: center;
gap: var(--Spacing-x2);
padding: 0 var(--Spacing-x3) var(--Spacing-x4);
overflow: auto;
}
.contentWithActions {
padding: 0;
}
.contentWithoutActions {
padding: 0 var(--Spacing-x3) var(--Spacing-x4);
}
.close {
background: none;
border: none;
@@ -12,6 +12,8 @@ export type ModalProps = {
onAnimationComplete?: VoidFunction
title?: string
subtitle?: string
withActions?: boolean
hideHeader?: boolean
} & (
| { trigger: JSX.Element; isOpen?: never; onToggle?: never }
| {
@@ -0,0 +1,17 @@
import { cva } from "class-variance-authority"
import styles from "./modal.module.css"
const config = {
variants: {
withActions: {
true: styles.contentWithActions,
false: styles.contentWithoutActions,
},
},
defaultVariants: {
withActions: false,
},
} as const
export const modalContentVariants = cva(styles.content, config)