Merged in feat/sw-2873-move-selecthotel-to-booking-flow (pull request #2727)
feat(SW-2873): Move select-hotel to booking flow * crude setup of select-hotel in partner-sas * wip * Fix linting * restructure tracking files * Remove dependency on trpc in tracking hooks * Move pageview tracking to common * Fix some lint and import issues * Add AlternativeHotelsPage * Add SelectHotelMapPage * Add AlternativeHotelsMapPage * remove next dependency in tracking store * Remove dependency on react in tracking hooks * move isSameBooking to booking-flow * Inject searchParamsComparator into tracking store * Move useTrackHardNavigation to common * Move useTrackSoftNavigation to common * Add TrackingSDK to partner-sas * call serverclient in layout * Remove unused css * Update types * Move HotelPin type * Fix todos * Merge branch 'master' into feat/sw-2873-move-selecthotel-to-booking-flow * Merge branch 'master' into feat/sw-2873-move-selecthotel-to-booking-flow * Fix component Approved-by: Joakim Jäderberg
This commit is contained in:
106
packages/booking-flow/lib/components/MapContainer/index.tsx
Normal file
106
packages/booking-flow/lib/components/MapContainer/index.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
"use client"
|
||||
|
||||
import { useCallback, useEffect, useRef, useState } from "react"
|
||||
|
||||
import { debounce } from "@scandic-hotels/common/utils/debounce"
|
||||
|
||||
import styles from "./mapModal.module.css"
|
||||
|
||||
export function MapContainer({ children }: { children: React.ReactNode }) {
|
||||
const [mapHeight, setMapHeight] = useState("")
|
||||
const [mapTop, setMapTop] = useState("")
|
||||
const [mapZIndex, setMapZIndex] = useState(0)
|
||||
const [scrollHeightWhenOpened, setScrollHeightWhenOpened] = useState(0)
|
||||
|
||||
const rootDiv = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
// Calculate the height of the map based on the viewport height from the start-point (below the header and booking widget)
|
||||
const handleMapHeight = useCallback(() => {
|
||||
const topPosition = rootDiv.current?.getBoundingClientRect().top ?? 0
|
||||
const scrollY = window.scrollY
|
||||
setMapHeight(`calc(100dvh - ${topPosition + scrollY}px)`)
|
||||
setMapTop(`${topPosition + scrollY}px`)
|
||||
setMapZIndex(11)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const originalOverflowY = document.body.style.overflowY
|
||||
|
||||
// Function to enforce overflowY to hidden
|
||||
const enforceOverflowHidden = () => {
|
||||
if (document.body.style.overflowY !== "hidden") {
|
||||
document.body.style.overflowY = "hidden"
|
||||
}
|
||||
}
|
||||
|
||||
// Set overflowY to hidden initially
|
||||
enforceOverflowHidden()
|
||||
|
||||
// Create a MutationObserver to watch for changes to the style attribute
|
||||
const observer = new MutationObserver(() => {
|
||||
enforceOverflowHidden()
|
||||
})
|
||||
|
||||
// Observe changes to the style attribute of the body
|
||||
observer.observe(document.body, {
|
||||
attributes: true,
|
||||
attributeFilter: ["style"],
|
||||
})
|
||||
|
||||
return () => {
|
||||
// Disconnect the observer on cleanup
|
||||
observer.disconnect()
|
||||
// Restore the original overflowY style
|
||||
document.body.style.overflowY = originalOverflowY
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Making sure the map is always opened at the top of the page,
|
||||
// just below the header and booking widget as these should stay visible.
|
||||
// When closing, the page should scroll back to the position it was before opening the map.
|
||||
useEffect(() => {
|
||||
// Skip the first render
|
||||
if (!rootDiv.current) {
|
||||
return
|
||||
}
|
||||
|
||||
if (scrollHeightWhenOpened === 0) {
|
||||
const scrollY = window.scrollY
|
||||
setScrollHeightWhenOpened(scrollY)
|
||||
window.scrollTo({ top: 0, behavior: "instant" })
|
||||
}
|
||||
}, [scrollHeightWhenOpened, rootDiv])
|
||||
|
||||
useEffect(() => {
|
||||
const debouncedResizeHandler = debounce(function () {
|
||||
handleMapHeight()
|
||||
})
|
||||
|
||||
const observer = new ResizeObserver(debouncedResizeHandler)
|
||||
|
||||
observer.observe(document.documentElement)
|
||||
|
||||
return () => {
|
||||
if (observer) {
|
||||
observer.unobserve(document.documentElement)
|
||||
}
|
||||
}
|
||||
}, [rootDiv, handleMapHeight])
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper} ref={rootDiv}>
|
||||
<div
|
||||
style={
|
||||
{
|
||||
"--hotel-map-height": mapHeight,
|
||||
"--hotel-map-top": mapTop,
|
||||
"--hotel-dynamic-map-z-index": mapZIndex,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
className={styles.dynamicMap}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
.dynamicMap {
|
||||
--hotel-map-height: 100dvh;
|
||||
--hotel-map-top: 145px;
|
||||
--hotel-dynamic-map-z-index: 2;
|
||||
position: fixed;
|
||||
top: var(--hotel-map-top);
|
||||
left: 0;
|
||||
height: var(--hotel-map-height);
|
||||
width: 100dvw;
|
||||
z-index: var(--hotel-dynamic-map-z-index);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
}
|
||||
.wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
Reference in New Issue
Block a user