Files
web/components/HotelReservation/HotelCardDialogListing/index.tsx
2024-12-17 16:33:00 +01:00

106 lines
3.0 KiB
TypeScript

"use client"
import { useCallback, useEffect, useRef } from "react"
import { useMediaQuery } from "usehooks-ts"
import { useHotelsMapStore } from "@/stores/hotels-map"
import useClickOutside from "@/hooks/useClickOutside"
import HotelCardDialog from "../HotelCardDialog"
import { getHotelPins } from "./utils"
import styles from "./hotelCardDialogListing.module.css"
import type { HotelCardDialogListingProps } from "@/types/components/hotelReservation/selectHotel/map"
export default function HotelCardDialogListing({
hotels,
}: HotelCardDialogListingProps) {
const hotelsPinData = hotels ? getHotelPins(hotels) : []
const activeCardRef = useRef<HTMLDivElement | null>(null)
const observerRef = useRef<IntersectionObserver | null>(null)
const dialogRef = useRef<HTMLDivElement>(null)
const isMobile = useMediaQuery("(max-width: 768px)")
const { activeHotelCard, setActiveHotelCard, setActiveHotelPin } =
useHotelsMapStore()
function handleClose() {
setActiveHotelCard(null)
setActiveHotelPin(null)
}
useClickOutside(dialogRef, !!activeHotelCard && isMobile, handleClose)
const handleIntersection = useCallback(
(entries: IntersectionObserverEntry[]) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const cardName = entry.target.getAttribute("data-name")
if (cardName) {
setActiveHotelCard(cardName)
}
}
})
},
[setActiveHotelCard]
)
useEffect(() => {
observerRef.current = new IntersectionObserver(handleIntersection, {
root: null,
threshold: 0.5,
})
const elements = document.querySelectorAll("[data-name]")
elements.forEach((el) => observerRef.current?.observe(el))
return () => {
elements.forEach((el) => observerRef.current?.unobserve(el))
observerRef.current?.disconnect()
}
}, [handleIntersection])
useEffect(() => {
if (activeCardRef.current) {
// Temporarily disconnect the observer
observerRef.current?.disconnect()
activeCardRef.current.scrollIntoView({
behavior: "smooth",
block: "nearest",
inline: "center",
})
// Reconnect the observer after scrolling
const elements = document.querySelectorAll("[data-name]")
setTimeout(() => {
elements.forEach((el) => observerRef.current?.observe(el))
}, 1000)
}
}, [activeHotelCard])
return (
<div className={styles.hotelCardDialogListing} ref={dialogRef}>
{!!hotelsPinData?.length &&
hotelsPinData.map((data) => {
const isActive = data.name === activeHotelCard
return (
<div
key={data.name}
ref={isActive ? activeCardRef : null}
data-name={data.name}
>
<HotelCardDialog
data={data}
isOpen={!!activeHotelCard}
handleClose={handleClose}
type="listing"
/>
</div>
)
})}
</div>
)
}