fix(BOOK-405): Pushing to history when opening sidepeek to avoid navigating back inside the booking flow

Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
Erik Tiekstra
2025-10-09 11:34:58 +00:00
parent 566dd54087
commit 527ab170b5
15 changed files with 674 additions and 584 deletions

View File

@@ -4,6 +4,7 @@ import { useEffect } from 'react'
import { Dialog, Modal, ModalOverlay } from 'react-aria-components'
import { useIntl } from 'react-intl'
import usePopStateHandler from '@scandic-hotels/common/hooks/usePopStateHandler'
import useSetOverflowVisibleOnRA from '@scandic-hotels/common/hooks/useSetOverflowVisibleOnRA'
import { IconButton } from '../../IconButton'
@@ -14,45 +15,72 @@ import SidePeekSEO from './SidePeekSEO'
import styles from './sidePeekSelfControlled.module.css'
import type { SidePeekSelfControlledProps } from './sidePeek'
interface SidePeekSelfControlledProps extends React.PropsWithChildren {
title: string
isOpen: boolean
onClose: () => void
}
export default function SidePeekSelfControlled({
children,
isOpen,
onClose,
title,
}: React.PropsWithChildren<SidePeekSelfControlledProps>) {
}: SidePeekSelfControlledProps) {
const intl = useIntl()
function handleClose(moveBack = false) {
if (moveBack) {
window.history.back()
} else {
onClose()
}
}
// Only register popstate handler when open
usePopStateHandler(() => handleClose(), isOpen)
useEffect(() => {
if (isOpen) {
window.history.pushState(null, '', window.location.href)
}
}, [isOpen])
return (
<>
<ModalOverlay className={styles.overlay} isDismissable>
<ModalOverlay
className={styles.overlay}
isDismissable
onOpenChange={() => handleClose(true)}
isOpen={isOpen}
>
<Modal className={styles.modal}>
<Dialog className={styles.dialog} aria-label={title}>
{({ close }) => (
<aside className={styles.sidePeek}>
<header className={styles.header}>
{title ? (
<Typography variant="Title/md" className={styles.heading}>
<h2>{title}</h2>
</Typography>
) : null}
<IconButton
theme="Black"
style="Muted"
onPress={close}
aria-label={intl.formatMessage({
defaultMessage: 'Close',
})}
>
<MaterialIcon
icon="close"
size={24}
color="Icon/Interactive/Default"
/>
</IconButton>
</header>
<div className={styles.sidePeekContent}>{children}</div>
<KeepBodyVisible />
</aside>
)}
<aside className={styles.sidePeek}>
<header className={styles.header}>
{title ? (
<Typography variant="Title/md" className={styles.heading}>
<h2>{title}</h2>
</Typography>
) : null}
<IconButton
theme="Black"
style="Muted"
onPress={() => handleClose(true)}
aria-label={intl.formatMessage({
defaultMessage: 'Close',
})}
>
<MaterialIcon
icon="close"
size={24}
color="Icon/Interactive/Default"
/>
</IconButton>
</header>
<div className={styles.sidePeekContent}>{children}</div>
<KeepBodyVisible />
</aside>
</Dialog>
</Modal>
</ModalOverlay>